Oracle查询优化-04插入、更新与删除数据
4.1 插入新記錄
問題
向表中插入一條新的記錄。
解決方案
使用帶有values子句的insert語句來插入一行。
insert into dept(deptno,dname,loc) values(19,'xgj','BEIJING');討論
作為一種簡便方式,在insert語句中,可以省略字段列表,
然而,如果語句中沒有列出要插入行中的目標字段,則必須要插入表中的所有列,需要注意的,在插入值列表中所列出的值的順序,必須與select * 查詢語句所列出的列順序完全一致。
4.2 插入默認值
問題
定義表時可以為某些列定義默認值。
create table test_xgj ( c1 varchar2(10) default '默認1', c2 varchar2(10) default '默認2', c3 varchar2(10) default '默認3', c4 date default sysdate );解決方案
SQL> insert into test_xgj(c1,c2,c3)values (default , null ,'手輸入');SQL> commit ;SQL> select * from test_xgj;C1 C2 C3 C4 ---------- ---------- ---------- ----------- 默認1 手輸入 2017-03-05討論
在值列表中的default關鍵字為相應列插入默認值,默認值在創建表時定義。 所有的dbms中都可以使用此關鍵字。
注意事項:
4.3 阻止對某幾列插入
問題
舉個例子,如果我們希望C4列的默認值為SYSDATE,這種列一般是為了記錄數據生成的時間,不允許手工錄入,該怎么辦么?
解決方案
我們可以建立一個不包含C4列的View,新增數據時通過這個VIEW就可以。
SQL> create or replace view test_xgj_view as select c1 , c2 ,c3 from test_xgj ;SQL> insert into test_xgj_view(c1,c2,c3) values ('默認值2',NULL ,'C3'); SQL> commit ;--查詢下 test_xgj表,發現 C4雖然沒有插入,但是因為設置了default值,所以也有值 SQL> select a.* from test_xgj a ;C1 C2 C3 C4 ---------- ---------- ---------- ----------- 默認值2 C3 2017-03-05 默認1 手輸入 2017-03-05討論
注意:
通過view新增數據,不能再使用關鍵字default .
SQL> insert into test_xgj_view(c1,c2,c3) values (default ,NULL ,'C3');insert into test_xgj_view(c1,c2,c3) values (default ,NULL ,'C3')ORA-32575: Explicit column default is not supported for modifying views4.3 復制表的定義及數據
解決方案
我們可以用一下語句 復制表EMP
create table emp2 as select * from emp ;也可以先復制表的定義,然后再新增數據
create table emp2 as select * from emp where 1=2;注意: 復制的表不包含默認值等約束信息,使用這種方式復制表后,需要重建默認值及索引和約束等信息。
舉例:
SQL> desc test_xgj; Name Type Nullable Default Comments ---- ------------ -------- ------- -------- C1 VARCHAR2(10) Y '默認1' C2 VARCHAR2(10) Y '默認2' C3 VARCHAR2(10) Y '默認3' C4 DATE Y sysdate --第一種方式 SQL> create table test_xgj_2 as select * from test_xgj ;Table createdSQL> desc test_xgj_2; Name Type Nullable Default Comments ---- ------------ -------- ------- -------- C1 VARCHAR2(10) Y C2 VARCHAR2(10) Y C3 VARCHAR2(10) Y C4 DATE Y SQL> ---第二種方式 SQL> create table test_xgj_copy as select * from test_xgj where 1=2 ;Table createdSQL> desc test_xgj_copy ; Name Type Nullable Default Comments ---- ------------ -------- ------- -------- C1 VARCHAR2(10) Y C2 VARCHAR2(10) Y C3 VARCHAR2(10) Y C4 DATE Y4.4 用with check option 限制數據錄入
如果視圖定義包括條件(譬如 WHERE 子句)并且其意圖是確保任何引用該視圖的 INSERT 或 UPDATE 語句都應用 WHERE 子句,則必須使用 WITH CHECK OPTION 定義該視圖。這個選項可以確保數據庫中正在修改的數據的完整性。如果在 INSERT 或 UPDATE 操作期間違反了條件,則返回 SQL 錯誤。
舉例說明:
我們創建一個視圖,并使用了with check option來限制了視圖。 然后我們來看一下視圖包含的結果
SQL> create or replace view xgj2 as3 select empno,ename from emp where ename like 'J%'4 with check option;View createdSQL> select * from xgj;EMPNO ENAME ----- ----------7566 JONES7900 JAMESSQL> update xgj set ename='XGJ' where empno=7566;update xgj set ename='XGJ' where empno=7566ORA-01402: view WITH CHECK OPTION where-clause violation--如果更新符合with check point的 ,則可以。 SQL> update xgj set ename='Jack' where empno=7566;1 row updatedSQL> rollback;Rollback completeORA-01402: 視圖 WITH CHECK OPTIDN 違反 where 子句的錯誤,為什么呢?
這是因為前面我們在創建視圖時指定了witch check option關鍵字,這也就是說,更新后的每一條數據仍然要滿足創建視圖時指定的where條件,所以我們這里發生了錯誤ORA-01402。
但是需要說明的時 ,雖然指定了with check option,我們還是可以刪除視圖中的數據。例如上例中,我們可以使用
delete from xgj where empno = 7566;INSERT WITH CHECK OPTION的用法
insert into (<select clause> WITH CHECK OPTION) values (...)SQL> insert into (select object_id,object_name,object_type from xgj where object_id<1000 WITH CHECK OPTION) 2 values(999,'xxx','xxxx');這樣的語法看起來很特殊,其實是insert進subquery里的這張表里,只不過如果不滿足subquery里的where條件的話,就不允許插入。
如果插入的列有不在subquery作為檢查的where條件里,那么也會不允許插入。
如果不加WITH CHECK OPTION則在插入時不會檢查。
這里注意,subquery其實是不會實際執行的。
4.5多表插入語句
oracle從9i開始可以用一條insert語句實現向多個表中插入數據
Oracle Insert all有三種情況:
一、無條件 INSERT ALL
二、條件 INSERT ALL
三、條件 INSERT FIRST
語法:
INSERT [ALL] [conditional_insert_clause] [insert_into_clause values_clause](subquery)subquery:子查詢語句,可以是任何合法的select語句
conditional_insert_clause如下:
[ALL][FIRST] [WHEN condition THEN][insert_into_clause values_clause] [ELSE] [insert_into_clause values_clause]無條件 INSERT ALL
語法
INSERT ALL insert_into_clause values_clause_1 [insert_into_clause values_clause_2] …… Subquery;示例:
INSERT ALL INTO sal_history(emp_id,hire_date,salary) values (empid,hiredate,sal) INTO mgr_history(emp_id,manager_id,salary) values (empid,hiredate,sal) SELECT employee_id empid,hire_date hiredate,salary sal,manager_id mgr FROM employees WHERE employee_id>200;1、指定所有跟隨著的多表 insert_into_clauses 執行無條件的多表插入;
2、對于每個由子查詢返回的行, Oracle 服務器執行每一個 insert_into_clause一次。
條件 INSERT ALL
INSERT ALL WHEN condition THEN insert_into_clause values_clause [WHEN condition THEN] [insert_into_clause values_clause] …… [ELSE] [insert_into_clause values_clause] Subquery;示例:
Insert All when id>5 then into z_test1(id, name) values(id,name) when id<>2 then into z_test2(id) values(id) else into z_test3 values(name) select id,name from xgj;1、指定 conditional_insert_clause 來執行一個條件多表插入;
2、Oracle 服務器通過相應的 WHEN 條件過濾每一個 insert_into_clause,確定是否執行這個 insert_into_clause;
3、一個單個的多表插入語句可以包含最多 127 個 WHEN 子句。
條件 INSERT FIRST
FIRST和ALL的區別在于當遇到第一個求值為true的子句之后,停止對WHEN子句求值,而ALL不論求值是否為true。
語法
INSERT FIRST WHEN condition THEN insert_into_clause values_clause [WHEN condition THEN] [insert_into_clause values_clause] …… [ELSE] [insert_into_clause values_clause] Subquery;1、Oracle 服務器對每一個出現在語句順序中的 WHEN 子句求值;
2、如果第一個 WHEN 子句的值為 true,Oracle 服務器對于給定的行執行相應的 INTO 子句,并且跳過后面的 WHEN 子句(后面的when語句都不再考慮滿足第一個When子句的記錄,即使該記錄滿足when語句中的條件)。
注:多表 INSERT 語句上的約束
a、你只能在表而不能在視圖上執行多表插入;
b、你不能執行一個多表插入到一個遠程表;
c、在執行一個多表插入時,你不能指定一個表集合表達式;
d、在一個多表插入中,所有的 insert_into_clauses 不能組合指定多于 999 個目列;
e、只有當所有insert_into_clauses中的表數據都沒有發生更新時,Rollback才會起作用。
4.6刪除違反參照 完整性的記錄
ORA-02298 未找到父項關鍵字
delete from emp where not exists (select null from dept where dept.deptno=emp.deptno );4.7刪除名稱重復的記錄
問題
數據如下:
SQL> create table xgj (id integer, name varchar(10));Table created SQL> INSERT INTO xgj VALUES (1, 'NAPOLEON');1 row inserted SQL> INSERT INTO xgj VALUES (2, 'DYNAMITE');1 row inserted SQL> INSERT INTO xgj VALUES (3, 'DYNAMITE');1 row inserted SQL> INSERT INTO xgj VALUES (4, 'SHE SELLS');1 row inserted SQL> INSERT INTO xgj VALUES (5, 'SEA SHELLS');1 row inserted SQL> INSERT INTO xgj VALUES (6, 'SEA SHELLS');1 row inserted SQL> INSERT INTO xgj VALUES (7, 'SEA SHELLS');1 row inserted SQL> commit ;Commit completeSQL>DYNAMITE 和 SEA SHELLS 重復,現在要求表中重復的name只保留一行,改如何辦呢?
解決方案
處理數據需謹慎,要確認更改結果后再提交。
下面介紹三種方法
通過name相同,id不同的方式來判斷
先查詢下數據,確認無誤
select *from xgj awhere exists (select nullfrom xgj bwhere a.name = b.nameand b.id > a.id);ID NAME -------- ----------2 DYNAMITE5 SEA SHELLS6 SEA SHELLS delete from xgj a where exists (select null from xgj b where a.name = b.name and b.id > a.id );利用這種方式刪除數據時,需要重建組合索引。
create index idx_name_id on xgj(name,id);利用rowid來代替其中的id
select *from xgj awhere exists (select nullfrom xgj bwhere a.name = b.nameand b.rowid > a.rowid);delete from xgj awhere exists (select nullfrom xgj bwhere a.name = b.nameand b.rowid > a.rowid);因為不需要關聯id列,我們只需要建立單列索引。
create index idx_name on xgj(name);通過分析函數根據name分組生成序號,然后刪除序號大于1的數據
查看要刪除的數據
select rowid as rid , name, row_number() over(partition by name order by id) as seqfrom xgj;RID NAME SEQ ------------------ ---------- ---------- AAAzBkAAIAAOet8AAB DYNAMITE 1 AAAzBkAAIAAOet8AAC DYNAMITE 2 AAAzBkAAIAAOet8AAA NAPOLEON 1 AAAzBkAAIAAOet8AAE SEA SHELLS 1 AAAzBkAAIAAOet8AAF SEA SHELLS 2 AAAzBkAAIAAOet8AAG SEA SHELLS 3 AAAzBkAAIAAOet8AAD SHE SELLS 17 rows selected刪除數據: 利用分析函數取出重復的數據后刪除序號>1的數據
delete from xgjwhere rowid in (select ridfrom (select rowid as rid,name,row_number() over(partition by name order by id) as seqfrom xgj)where seq > 1);當然了 還有其他方法。。
總結
以上是生活随笔為你收集整理的Oracle查询优化-04插入、更新与删除数据的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Dubbo-入门指南+实例
- 下一篇: Oracle查询优化-05元数据查询