我有一个任务是读取一个大文件并将包含的数据插入到SQL数据库中。在"真实"任务,几个表中有10列,但为了便于讨论,我将使用更简单的模式。
数据如下所示: FName,LName,Address。
因此,我声明一个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?,另一个Stacker向我解释说INSERT语句与OUTPUT语句一起使用来保存有关多个插入行的信息。
我认为我想做的就是拥有一个临时表,不仅可以保存传入的数据,还可以保存与每个人相关的主键和外键:一个可以保存Fname,Lname的表, Address,PersonId和AddressId。
但是,据我所知,我可以使用OUTPUT关键字在临时表中创建新行,但我不知道如何使用它来修改现有行。
我觉得这个任务应该不难,所以我该怎么做?
我的SQL服务器是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 |
----+----------------------+
答案 0 :(得分: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