子查詢在INSERT語句中的應用


在使用INSERT語句的時候,一般都是使用它向數據庫中一條條的插入數據,比如:


INSERT INTO MyTable(FId,FName,FAge)VALUES(1,"John",20) 

但是有時我們可能需要將數據批量插入表中,比如創建一個和T_ReaderFavorite表結構完全相同的表T_ReaderFavorite2,然后將T_ReaderFavorite 中的輸入復制插入到T_ReaderFavorite2表。

首先我們創建T_ReaderFavorite2 表:


MYSQL,MSSQLServer,DB2:

CREATE TABLE T_ReaderFavorite2 (FCategoryId INT,FReaderId INT) Oracle: CREATE TABLE T_ReaderFavorite2 (FCategoryId NUMBER (10),FReaderId NUMBER (10)) 

按照普通的實現思路,我們需要編寫如下的宿主語言代碼:


rs = ExecuteQuery("SELECT * from T_ReaderFavorite"); while(rs.next()) { int categoryId = rs.get("FCategoryId"); int readerId = rs.get("FReaderId"); Execute("INSERT INTo T_ReaderFavorite2(FCategoryId,FReaderId) VALUES(?,?)", categoryId, readerId); } 

在宿主語言中逐條讀取T_ReaderFavorite表中的記錄,然后將它們逐條插入T_ReaderFavorite2表中。這樣的處理方式能夠正確的完成要求的功能,而且由於目前T_ReaderFavorite 表中的數據量非常少,所以這樣處理速度上也沒有什么影響。但是如果T_ReaderFavorite 表中有大量的數據的話,由於每插入一條數據都要執行兩次數據庫操作,所以這種處理方式效率非常低,因此必須采用其他的處理方式。

除了INSERT……VALUES……這種用法外,INSERT語句還支持另外一種語法,那就是INSERT……SELECT……,采用這種使用方式可以將SELECT語句返回的結果集直接插入到目標表中,因為這一切都是都數據庫內部完成的,所以效率非常高。下面看一下使用INSERT……SELECT……來實現將T_ReaderFavorite中的輸入復制插入到T_ReaderFavorite2表,SQL語句如下:


INSERT INTO T_ReaderFavorite2(FCategoryId,FReaderId) SELECT FCategoryId,FReaderId FROM T_ReaderFavorite 

這里使用SELECT FCategoryId,FReaderId FROM T_ReaderFavorite將T_ReaderFavorite表中的數據讀出,然后使用INSERT INTO T_ReaderFavorite2(FCategoryId,FReaderId)將檢索結果插入到T_ReaderFavorite2 表中,注意上下的列順序必須是一一對應的。

執行完畢我們后我們查看T_ReaderFavorite2 表中的內容:


FCategoryId FReaderId

1 1

5 2

2 3

3 4

5 5

1 6

1 7

4 8

6 9

5 10

2 11

2 12

1 12

3 1

1 3

4 4

可以看到T_ReaderFavorite表中的數據已經被正確的復制到T_ReaderFavorite2 表中了。

使用INSERT……SELECT……不僅能夠實現簡單的將一個表中的數據導出到另外一個表中的功能,還能在將輸入插入目標表之前對數據進行處理,比如下面的SQL 語句用於將T_ReaderFavorite表中的數據復制到T_ReaderFavorite2 表中,但是如果T_ReaderFavorite表中的FReaderId 列的值大於10,則將FReaderId 的值減去FCategoryId 的值后再復制到T_ReaderFavorite2 表中。編寫如下的SQL語句:


INSERT INTO T_ReaderFavorite2(FCategoryId,FReaderId) SELECT FCategoryId,(CASE WHEN FReaderId<=10 THEN FReaderId ELSE FReaderId- FCategoryId END) FROM T_ReaderFavorite 

這里在SELECT 語句中使用CASE 函數來實現對數據插入前的處理。執行完畢我們后我們查看T_ReaderFavorite2 表中的內容:


FCategoryId FReaderId

1 1

5 2

2 3

3 4

5 5

1 6

1 7

4 8

6 9

5 10

2 9

2 10

1 11

3 1

1 3

4 4

使用這種插入前的數據處理可以完成諸如“將數據從A表導出到B表,並且將B表的主鍵全部加上bak前綴”、“將A公司的所有員工插入到我們的會員表,自動導入所有的客戶信息,並且為其自動生成會員編號”等復雜的任務。

因為可以在插入目標表前可以對數據進行處理,所以INSERT……SELECT……語句不局限於同結構表間的數據插入,也可以實現異構表見輸入的插入。假設要將所有會員愛好的圖書統一增加“小說”,也就是為T_Reader 表中的每個讀者都在T_ReaderFavorite表中創建一條FCategoryId等於1 的記錄,實現SQL語句如下:


INSERT INTO T_ReaderFavorite(FCategoryId,FReaderId) SELECT 1,FId FROM T_Reader 

SELECT語句從T_Reader表中檢索所有的讀者信息,並且將第一列設定為固定值1,而將第二列設定為讀者的主鍵,執行完畢查看T_ReaderFavorite表中的內容:


FCategoryId FReaderId

1 1

5 2

2 3

3 4

5 5

1 6

1 7

4 8

6 9

5 10

2 11

2 12

1 12

3 1

1 3

4 4

1 1

1 2

1 3

1 4

1 5

1 6

1 7

1 8

1 9

1 10

1 11

1 12

數據被正確的插入了,但是仔細查看T_ReaderFavorite表中的內容,不難發現其中有重復的數據,比如FCategoryId等於1、FReaderId等於1的記錄出現了兩次,這就出現了數據冗余,必須修改SQL語句防止這種情況的發生。也就是在將輸入插入T_ReaderFavorite表之前要檢查T_ReaderFavorite表中是否已經存在了同樣的數據。

在繼續進行之前請首先清空T_ReaderFavorite 表中的數據,然后執行開頭的T_ReaderFavorite表數據的初始化代碼。

首先需要在SELECT語句中添加WHERE子句,這個WHERE子句檢查每個讀者是否有Story的愛好,即是否存在圖書分類主鍵為1的的愛好,只有沒有的時候才返回記錄:


SELECT 1,FId FROM T_Reader WHERE NOT EXISTS ( SELECT * FROM T_ReaderFavorite WHERE T_ReaderFavorite. FCategoryId=1 AND T_ReaderFavorite. FReaderId= T_Reader.FId ) 

執行這個子查詢片段,執行完畢我們就能在輸出結果中看到下面的執行結果:


FId

1 2

1 4

1 5

1 8

1 9

1 10

1 11

可以看到檢索出的確實是還沒有以Story做為愛好的讀者,所以編寫下面的SQL語句來執行數據的插入:


INSERT INTO T_ReaderFavorite(FCategoryId,FReaderId) SELECT 1,FId FROM T_Reader WHERE NOT EXISTS ( SELECT * FROM T_ReaderFavorite WHERE T_ReaderFavorite. FCategoryId=1 AND T_ReaderFavorite. FReaderId= T_Reader.FId ) 

執行完畢查看T_ReaderFavorite表中的內容:


FCategoryId FReaderId

1 1

5 2

2 3

3 4

5 5

1 6

1 7

4 8

6 9

5 10

2 11

2 12

1 12

3 1

1 3

4 4

1 2

1 4

1 5

1 8

1 9

1 10

1 11

可以看到表中的數據沒有重復的了,即使重復執行這個SQL 語句也都不會添加新的記錄,因為這個SQL語句已經對數據的重復做了檢查。


免責聲明!

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



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