2015-02-09 156 views
0

我有一個任務來讀取大文件並將包含的數據插入到SQL數據庫中。在「真正的」任務中,幾個表中有10列,但爲了討論,我將使用更簡單的模式。數據如下: FName,LName,Address。如何將數據批量插入到兩個SQL表中

因此,我聲明一個SQL類型BulkInsertData來保存這三個字段,以便它們可以作爲表值參數傳入。

這裏是我的表:

dbo.Person 
---+-------+-------+----------+ 
Id | Fname | Lname | AddressId| 
---+-------+-------+----------+ 
1 | Bob | Smith |  42 | 
2 | Sue | Baker |  234 | 
---+-------+-------+----------+ 

dbo.Address 
----+----------------------+ 
Id | Address    | 
----+----------------------+ 
42 | 1600 Pennsylvania Ave| 
234 | 10 Downing St  | 
----+----------------------+ 

我的目標是第一個和最後一個名稱插入dbo.Person表和dbo.Address表中的地址,用適當的外鍵一起。將數據插入多個表格很容易,但我堅持使用外鍵關係。

如果我只插入一條記錄,我可能會將地址插入到dbo.Address表中,然後使用SELECT @@IDENTITY獲取要插入到dbo.Person中的新地址的ID以及第一個和最後一個名稱。

這裏,Does SQL Server have something like @@IDENTITY that returns multiple values?,另一個堆棧器向我解釋說,INSERT語句與OUTPUT語句一起使用可以保存有關多個插入行的信息。

我認爲我想要做的是創建一個臨時表,該表不僅包含傳入的數據,還包含與每個人關聯的主鍵和外鍵:一個可以存放Fname,Lname ,地址,PersonId和AddressId。

但據我所知,我可以使用OUTPUT關鍵字在臨時表中創建新行,但我不知道如何使用它來修改現有行。

我覺得這個任務不應該很難,所以我該怎麼做?

我的SQL Server是MS SQL Server 2008的

如果我把下面的數據...

Adam, Dumas, 300 Broadway 
Greg, Ho, 213 Main St 

和散裝將其插入到我上述的表格,結果應該是這樣的:

dbo.Person 
---+-------+-------+----------+ 
Id | Fname | Lname | AddressId| 
---+-------+-------+----------+ 
1 | Bob | Smith |  42 | 
2 | Sue | Baker |  234 | 
3 | Adam | Dumas |  501 | 
4 | Greg | Ho |  502 | 
---+-------+-------+----------+ 

dbo.Address 
----+----------------------+ 
Id | Address    | 
----+----------------------+ 
42 | 1600 Pennsylvania Ave| 
234 | 10 Downing St  | 
501 | 300 Broadway   | 
502 | 213 Main St   | 
----+----------------------+ 

回答

5
CREATE TABLE TVP_ADDRESS 
(
ID INT IDENTITY(1,1) PRIMARY KEY,ADDRESS VARCHAR(100) 
) 

CREATE TABLE TVP_PERSON 
(
ID INT IDENTITY(1,1) PRIMARY KEY,FNAME VARCHAR(100),LNAME VARCHAR(100),ADDRESS_ID INT,CONSTRAINT fk_address_id_tvp_address FOREIGN KEY(address_id) REFERENCES tvp_address(id) ON DELETE CASCADE 
) 

CREATE TYPE TVPDATA 
AS 
TABLE 
(
FNAME VARCHAR(100),LNAME VARCHAR(100),ADDRESS VARCHAR(100) 
) 
GO 
CREATE PROCEDURE inser_tvpdata 
(
@TVP TVPDATA READONLY 
) 
AS 
BEGIN 
    DECLARE @T TABLE(ID INT,ADDRESS VARCHAR(100)) 

--first insert address get ids 

    INSERT INTO TVP_ADDRESS(address) OUTPUT Inserted.* INTO @T 
    SELECT DISTINCT 
    t.address 
    FROM @TVP t --LEFT OUTER JOIN TVP_address td ON t.address = td.address 
    --WHERE td.address IS NULL 
    -- insert persons and get new ids 

    INSERT INTO tvp_person(Fname,lname,address_id) 
    SELECT t.fname,t.lname,temp.id 
    FROM @TVP t 
    INNER JOIN @T temp ON temp.ADDRESS=t.address 
END 
GO 
DECLARE @t TVPDATA 

INSERT INTO @t(fname,lname,address) VALUES ('john','r','test'),('steve','r','test2') 

EXEC inser_tvpdata @t 

SELECT * 
FROM TVP_ADDRESS 

SELECT * 
FROM TVP_PERSON 
+0

SQL可能是由沒有試圖做一個單行這麼多東西更易讀,但在其他看起來不錯。 +1 – 2015-02-09 21:49:07

+1

我錯了嗎,還是這個代碼假設'Address'中的值是唯一的?我不能做出這樣的假設。 – 2015-02-10 00:36:54

+0

我做得有點不同,但你讓我指出了正確的方向。謝謝! – 2015-02-10 21:08:45