2015-02-09 66 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

相关问题