【问题标题】:Update record's foreign key field based on a newly inserted record's primary key根据新插入的记录主键更新记录外键字段
【发布时间】:2023-04-11 05:01:01
【问题描述】:

对于表 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())

有什么想法吗?

【问题讨论】:

  • 对不起,我错过了这个信息。删除评论。

标签: sql sql-server


【解决方案1】:

您可以使用游标循环遍历 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

【讨论】:

    【解决方案2】:

    在 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 解决方案的低效使用。

    【讨论】:

      【解决方案3】:

      我发现的另一种方法是使用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)
      

      【讨论】:

        猜你喜欢
        • 2013-09-13
        • 1970-01-01
        • 2013-04-05
        • 2017-04-16
        • 1970-01-01
        • 2015-07-22
        • 2015-12-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多