根据新插入的记录的主键更新记录的外键字段

时间:2012-07-29 14:45:46

标签: sql sql-server

对于表A中的每条记录,我想根据表B中新插入记录的scope_identity更新其中一个字段的外键值。

我需要在表B中为表A中的每条记录创建一条新记录,以便接收外键(scope_identity)值。

例如,对于下表中的每一行,我想基于在表B中创建新的行/外键来更新空外键字段。

表A:

|Id|ForeignKey|
|1 |NULL      |
|2 |NULL      |
|3 |NULL      |
|4 |NULL      |
|5 |NULL      |

作为一个伪代码我想到了像这样的SQL:

update TableA 
set ForeignKey = (INSERT INTO TableB VALUES (value1) select SCOPE_IDENTITY())

有什么想法吗?

3 个答案:

答案 0 :(得分:5)

您可以使用游标循环遍历TableA并创建记录:

DECLARE @Id int
DECLARE @ForeignKey int

DECLARE C CURSOR FOR SELECT Id FROM TableA

OPEN C

FETCH NEXT FROM C INTO @Id

WHILE @@FETCH_STATUS = 0
BEGIN
    INSERT INTO TableB VALUES (value1)
    SET @ForeignKey = SCOPE_IDENTITY()

    UPDATE TableA
    SET ForeignKey = @ForeignKey
    WHERE Id = @Id

    FETCH NEXT FROM C INTO @Id
END

CLOSE C
DEALLOCATE C

答案 1 :(得分:0)

在SQL Server 2008及更高版本中执行与INSERT相关的UPDATE的基于集合的方法是使用MERGE...OUTPUT语句。

-- This table variable will hold the correlation between the two tables
declare @NewLinks table (dst_id int, src_id int)

merge TableB dst
using TableA src
    on 1 = 0 --inserts all from src into dst, add WHERE-like limit here
when not matched --should never match, since this is an INSERT-like query
    insert (<dst_column_list>) values (<src_column_list>)
output INSERTED.<dst_surrogate_key>, src.<src_surrogate_key>
into @NewLinks

update src
set src.ForeignKey = nl.dst_id
from TableA src
join @NewLinks nl
    on nl.src_id = src.Id

由于INSERT语句(即使在INSERT ... SELECT表单中)没有FROM子句,因此无法在其OUTPUT子句中引用from_table_name来捕获完整的相关性。由于MERGE始终将其USING子句视为FROM子句,因此它可用于模拟INSERT ... SELECT构造,同时允许访问OUTPUT中的源表和目标表。

使用MERGE ... OUTPUT创建与INSERT相关的UPDATE,使用游标或循环替换RBAR解决方案的低效使用,并维护单个临时表或表值变量。

答案 2 :(得分:0)

我发现的另一种方法是使用ROW_NUMBER function任意联接表,然后使用派生的查询更新FK。这个想法是tableA和tableB之间没有的关系,我们只需要链接它们即可获取新的外键。将它们连接到诸如ROW_NUMBER之类的任意对象上,可以为我们提供一种方法来选择一行以从中获取ID。

首先创建新记录

INSERT INTO TableB VALUES (value1)

在ROW_NUMBER上写任意将它们联接的查询(我们将在下一步中使用它)

SELECT
    tableARows.Id, 
    tableBRows.TheNewId
FROM
(
    SELECT Id, Row =  ROW_NUMBER() OVER (ORDER BY Id) FROM tableA
)tableARows INNER JOIN
(
    SELECT TheNewId, Row = ROW_NUMBER() OVER (ORDER BY TheNewId) FROM tableB
)tableBRows ON tableARows.Row = tableBRows.Row

然后是完整的UPDATE语句,用来自tableB的新FK填充tableA

UPDATE tableA 
SET tableA.ForeignKey = LinkedKeys.TheNewId
FROM
(
    SELECT
        tableARows.Id, 
        tableBRows.TheNewId
    FROM
    (
        SELECT Id, Row =  ROW_NUMBER() OVER (ORDER BY Id) FROM tableA
    )tableARows INNER JOIN
    (
        SELECT TheNewId, Row = ROW_NUMBER() OVER (ORDER BY TheNewId) FROM tableB
    )tableBRows ON tableARows.Row = tableBRows.Row
)LinkedKeys INNER JOIN
tableA  ON tableA.Id = LinkedKeys.Id

这是我使用的示例表定义。

CREATE TABLE tableA (Id INT, ForeignKey INT)
INSERT INTO tableA VALUES (100,NULL),(200,NULL),(300,NULL)


CREATE TABLE tableB (TheNewId INT)
INSERT INTO tableB VALUES(5000),(6000),(7000)