1. 程式人生 > >Oracle查詢優化改寫_4

Oracle查詢優化改寫_4

對應的第四章”插入,更新與刪除“


1.阻止對某幾列插入

向資料庫某張表【包含欄位A,B,C,D】中插入資料時,這張表內的一個或多個欄位【D】不允許手動錄入。此時,可以建立一個不包含“D”欄位的VIEW,新增資料時通過這個VIEW插入即可。

creat table TEST (A vachar2(20) default '預設1',B vachar2(20) default '預設2',C vachar2(20) default '預設3',D date default sysdate);

creat or replace view v_test as select A,B,C from test;

/*插入資料*/
insert into v_test (A,B,C) values ('我的輸入',null,'別動 d');

執行這條語句,生成一條新的記錄,該記錄的“D”欄位為預設值。

/*通過VIEW新增資料,不能使用 關鍵字 default*/
 insert into v_test (A,B,C) values (default, null, '別動 d');
2.複製表的定義及資料

1)複製表

    CREATE TABLE test_zyh2 AS SELECT * FROM TEST_ZYH; 

2)複製表的定義

    CREATE TABLE test_zyh2 AS SELECT * FROM TEST_ZYH  WHERE 1 = 2;

注意:複製的表不包含預設值等約束資訊,使用這種方式複製表後,需要重建預設值及索引和約束等資訊。

3.插入資料欄位限制

1)對插入的資料,做限制

    ALTER TABLE TEST_ZYH
ADD CONSTRAINT chech_num CHECK (NUM > 5);


ALTER TABLE TEST_ZYH
ADD CONSTRAINT check_C4 CHECK (C4 > SYSDATE);

/*報錯:日期或系統變數在 CHECK 約束條件中指定錯誤*/

2)使用 WITH CHECK OPITION限制駛入

insert into (select empno,empmame,hiredete from emp where hiredete<= SYSDATE WITH CHECK OPTION) VALUES (9999,'',SYSDATE +1)

(select empno,empmame,hiredete from emp where hiredete<= SYSDATE WITH CHECK OPTION) 被當做一個檢視處理。

當規則比較複雜,可以用 2) 實現約束。

4.多表插入

1)無條件 INSERT

CREATE TABLE EMP1 AS SELECT EMPNO,ENAME,JOB FROM EMP WHERE 1=2;
CREATE TABLE EMP2 AS SELECT EMPNO,ENAME,DEPTNO FROM WHERE 1=2;

INSERT ALL
    INTO EMP1(EMPNO,ENAME,JOB) VALUES (EMPNO,ENAME,JOB)
    INTO EMP2(EMPNO,ENAME,DEPTNO) VALUES (EMPNO,ENAME,DEPTNO)
SELECT EMPNO,ENAME,JOB,DEPTNO FROM EMP WHERE DEPTNO IN (10,20);

因為沒有加條件,所以會同時向兩張表中插入資料,且兩個表中,插入的資料條數一樣。

2)有條件 INSERT

INSERT ALL
    WHEN JOB IN ('SALESMAN','MANAGER') THEN 
        INTO EMP1(EMPNO,ENAME,JOB) VALUES (EMPNO,ENAME,JOB)
    WHEN DEPTNO IN ('20','30') THEN
        INTO EMP2(EMPNO,ENAME,DEPTNO) VALUES (EMPNO,ENAME,DEPTNO)
SELECT EMPNO,ENAME,JOB,DEPTNO FROM EMP;

根據設定的條件,只有滿足條件的資料才會插入對應的表,如果某條資料,滿足多個條件,則這條資料會被插入到多張表中。

3)有條件 INSERT FIRST

INSERT FIRST
    WHEN JOB IN ('SALESMAN','MANAGER') THEN 
        INTO EMP1(EMPNO,ENAME,JOB) VALUES (EMPNO,ENAME,JOB)
    WHEN DEPTNO IN ('20','30') THEN
        INTO EMP2(EMPNO,ENAME,DEPTNO) VALUES (EMPNO,ENAME,DEPTNO)
SELECT EMPNO,ENAME,JOB,DEPTNO FROM EMP;

INSERT FIRST語句中,當第一個表符合條件後,第二個表將不再插入對應的行,表emp2中不再有與emp1相同的資料,也就是INSERT FIRST 與 INSERT ALL的不同之處。

4)轉置 INSERT

轉置 INSERT 與其說是一個分類,不如算作“INSERT ALL”的一個用法。

CREAT TABLE T2(d VACHAR2(10),des VACHAR2(50));

CREAT TABLE T1 AS 
SELECT 
    '熊樣,精神不佳' AS d1,
    '貓樣,溫馴聽話' AS d2,
    '狗樣,神氣活現' AS d3,
    '鳥樣,嚮往明天' AS d4,
    '花樣,像花兒一樣快樂' as d5
FROM dual;    

/* 轉置 INSERT */
INSERT ALL
    INTO t2(d,des) VALUES ('週一',d1)
    INTO t2(d,des) VALUES ('週二',d2)
    INTO t2(d,des) VALUES ('週三',d3)
    INTO t2(d,des) VALUES ('週四',d4)
    INTO t2(d,des) VALUES ('週五',d5)
SELECT d1,d2,d3,d4,d5 FROM T1;

/*查詢結果*/
SELECT * FROM T2;

D           DES
----------------
週一        熊樣,精神不佳
週二        貓樣,溫馴聽話 
週三        狗樣,神氣活現
週四        鳥樣,嚮往明天
週五        花樣,像花兒一樣快樂
5 rows selected

可以看到,轉置 INSERT 的實質就是把不同列的資料插入到同一表的不同行中。

轉置 INSERT 的等價語句如下:

INSERT INTO T2(d,des)
    SELECT '週一',d1 FROM T1 UNION ALL
    SELECT '週二',d2 FROM T1 UNION ALL
    SELECT '週三',d3 FROM T1 UNION ALL
    SELECT '週四',d4 FROM T1 UNION ALL
    SELECT '週五',d5 FROM T1 ;
5.合併記錄【MERGE INTO】
MERGE INTO 語法
MERGE INTO table_name A 
USING (table|view|query_sql) B
ON (A.col = B.col) 
WHEN MATCHED THEN 
    UPDATE SET A.col1 = B.col_val1 [where 條件1]
    /* where 條件只出現一次,這裡新增where條件1,那麼 delete 後面的where條件2就無效*/
    [DELETE] [where 條件2]
WHEN NOT MATCHED THEN 
    INSERT (column_list) VALUES (column_values) [ where 條件3]
    /* 這裡是 A表中不存在對應的資料時,才會新增*/

注意:
    1)只能更改 A,不可以更新B。
    2)更新,刪除,插入這三個操作同時進行,不分先後。
    3)where 條件只出現一次,這裡新增where條件,那麼 delete 後面的where就無效。此時 update的範圍是:(A.col = B.col)減去範圍[where 條件2]
6.刪除名稱重複的記錄
create table dupes (id integer,name vachar(10));
insert into dupes values(1,'ZYH');
insert into dupes values(2,'ZYH');
insert into dupes values(3,'YYR');
insert into dupes values(4,'YYR');
insert into dupes values(5,'YYR');
insert into dupes values(6,'YNN');
insert into dupes values(7,'YNN');

1)通過name相同。id不同的方式來判斷。

delete from dupes a 
    where exists (select null from dupes b where b.name = a.name and b.id > a.id) 

/* 利用這種方式刪除資料時,需要建組合索引 */

create index idx_name_id on dupes(name,id);

2)用 ROWID 來代替其中的 id。

delete from dupes a
    where exists (select /*+ hash_sj */ null from dupes b where b.name = a.name and b.rowid > a.rowid);

/* 因為不需要關聯id列,只需要建立單列索引*/

create  index idx_name on dupes(name);

3)通過分析函式根據 name 分組生成序號,然後刪除序號大於1的資料。

delete from dupes where rowid in 
    (
    select rid from
        (
        select rowid as rid,ROW_NUMBER() OVER(PARTITION BY NAME order by id) as seq from dupes
        )
    where  seq > 1  
    );