理解insert all/insert first的使用


      在常用的SQL寫法中我們會經常遇到把一個表的數據插入另外一張表的情況,這是一個insert into 表名 select .... from 表名   就可以解決了。但是如果是把一張表的數據同時插入兩張表或兩張以上的表該怎么辦?你是不是已經想到了辦法了,使用多個insert into
語句,例如:

insert into test1 select * from test;
insert into test2 select * from test;
......
commit;

 

       通過把多張表的插入腳本放入一個事務中解決(如上),但是這樣做的結果有可能是test1表和test2表結果集不一樣,因為這個事務中插入的源數據表test被讀取了兩次,在一個表數據變化較快的情況下,兩次讀取的數據可能會不一樣,這就違反了我們之前的需求。如何解決?? 這種情況下我們可以把原表數據預先讀到的一個全局臨時表里,然后再從臨時表里讀出數據插入多個目的表,當然,引入我們本文的話題,使用insert all更為方便解決。

       insert all分為無條件插入和有條件插入,在有條件插入的情況下還可以使用insert first,他與insert all會有一點小區別,在下面的例子中我們將會介紹。

 

1,insert all無條件插入

---構造一個環境

SQL> drop table test;
 
Table dropped
 
SQL> drop table test1;
 
Table dropped
 
SQL> drop table test2;
 
Table dropped
 
SQL> create table test as select deptno,dname from dept;
 
Table created
 
SQL> create table test1 as select * from test where 1=2;
 
Table created
 
SQL> create table test2 as select * from test where 1=2;
 
Table created
 
SQL> select count(*) from test;
 
  COUNT(*)
----------
         4
 
SQL> select count(*) from test1;
 
  COUNT(*)
----------
         0
 
SQL> select count(*) from test1;
 
  COUNT(*)
----------
         0

 

--插入數據

SQL> insert all 
  2  into test1(deptno,dname)
  3  into test2(deptno,dname)
  4  select deptno,dname from test;
 
8 rows inserted
 
SQL> select count(*) from test1;
 
  COUNT(*)
----------
         4
 
SQL> select count(*) from test2;
 
  COUNT(*)
----------
         4
 
SQL> commit;
 
Commit complete

      可以看到我們使用一個SQL語句實現了插入了多張表數據,而且這種方式要比寫多個insert into 語句效率要高。在上面的SQL中不論插入多少張表,test表只會被讀取一次。

 

 

2,帶條件的insert all插入

 

SQL> select * from test;
 
DEPTNO DNAME
------ --------------
    10 ACCOUNTING
    20 RESEARCH
    30 SALES
    40 OPERATIONS
 
SQL> truncate table test1;
 
Table truncated
 
SQL> truncate table test2;
 
Table truncated
 
SQL> insert all
  2  when deptno <30 then
  3  into test1(deptno,dname)
  4  when deptno <50 then
  5  into test2(deptno,dname)
  6  select deptno,dname from test;
 
6 rows inserted
 
SQL> select * from test1;
 
DEPTNO DNAME
------ --------------
    10 ACCOUNTING
    20 RESEARCH
 
SQL> select * from test2;
 
DEPTNO DNAME
------ --------------
    10 ACCOUNTING
    20 RESEARCH
    30 SALES
    40 OPERATIONS
 
SQL> commit;
 
Commit complete


       從上面的SQL中我們可以當有帶條件的插入后,因為test1和test2表對應的條件不同,插入到兩張表的數據也不同,這說明插入條件起來作用。test1的條件是部門號小於30的放入test1表,test2的條件是部門號小於50的放入test2表,從test表中查出的4條數據,每條數據都經過了這兩個條件的判斷(過濾)。

 

3,帶條件的insert fist插入

 

SQL> truncate table test1;
 
Table truncated
 
SQL> truncate table test2;
 
Table truncated
 
SQL> select * from test;
 
DEPTNO DNAME
------ --------------
    10 ACCOUNTING
    20 RESEARCH
    30 SALES
    40 OPERATIONS
 
SQL> insert first
  2  when deptno <30 then
  3  into test1(deptno,dname)
  4  when deptno <50 then
  5  into test2(deptno,dname)
  6  select deptno,dname from test;
 
4 rows inserted
 
SQL> select * from test1;
 
DEPTNO DNAME
------ --------------
    10 ACCOUNTING
    20 RESEARCH
 
SQL> select * from test2;
 
DEPTNO DNAME
------ --------------
    30 SALES
    40 OPERATIONS
 
SQL> commit;
 
Commit complete

        從test1和test2的結果輸出我們會發現test1數據是正常的,而test2貌似數據少了,因為部門10、部門20也符合 deptno<50的條件,為什么沒有插入進去那?其實不然,insert first是考慮先后關系的,如果有數據滿足第一個when條件又滿足第二個when條件,則執行第一個then插入語句,第二個then就不插入第一個then已經插入過的數據了。反之有數據不滿足第一個when條件且滿足第二個when條件,則數據會插入第二個條件下對應的表中,這也正是insert first與inset all的區別。

       簡單來說就是all只要滿足條件,就會插入;first只要有一個滿足條件,后面的條件不再判斷。

 

注意:insert all 無法支持序列插入,會導致兩邊不一致,舉例如下:

SQL> truncate table test1;
 
Table truncated
 
SQL> truncate table test2;
 
Table truncated
 
SQL> create sequence seq_test;
 
Sequence created
 
SQL> insert all
  2  into test1(deptno,dname)
  3  into test2(deptno,dname)
  4  select seq_test.nextval deptno,dname from test;
 
insert all
into test1(deptno,dname)
into test2(deptno,dname)
select seq_test.nextval deptno,dname from test
 
ORA-02287: 此處不允許序號      --不能直接使用序列

 

SQL> CREATE OR REPLACE FUNCTION F_SEQ RETURN NUMBER AS
  2   V_SEQ NUMBER;
  3   BEGIN
  4   SELECT SEQ_TEST.NEXTVAL INTO V_SEQ FROM DUAL;
  5   RETURN V_SEQ;
  6   END;
  7  /
 
Function created
 
SQL> insert all
  2  into test1(deptno,dname)
  3  into test2(deptno,dname)
  4  select f_seq deptno,dname from test;
 
8 rows inserted
 
SQL> commit;
 
Commit complete
 
SQL> select * from test1;
 
DEPTNO DNAME
------ --------------
     1 ACCOUNTING
     3 RESEARCH
     5 SALES
     7 OPERATIONS
 
SQL> select * from test2;
 
DEPTNO DNAME
------ --------------
     2 ACCOUNTING
     4 RESEARCH
     6 SALES
     8 OPERATIONS


  從上面的SQL結果中我們可以看到test1和test2表deptno值出現了不一樣,這就是說insert all 無法支持序列插入,會導致兩邊不一致。

 

 

 

可參考:

http://blog.itpub.net/29196873/viewspace-1122075/

http://blog.csdn.net/ghostgant/article/details/5700228

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM