【问题标题】:How to fix this stored procedure problem如何解决此存储过程问题
【发布时间】:2010-08-12 19:14:11
【问题描述】:

我有 2 张桌子。以下只是这些表格的精简版。

TableA
Id <pk> incrementing
Name varchar(50)

TableB
TableAId <pk> non incrementing
Name varchar(50)

现在这些表相互关联。

场景

用户 1 来到我的站点并执行了一些操作(在这种情况下,将行添加到表 A)。所以我使用 SqlBulkCopy 表 A 中的所有这些数据。

但是,我还需要将数据添加到表 B,但我不知道表 A 中新创建的 Id,因为 SQLBulkCopy 不会返回这些。

所以我正在考虑使用一个存储过程来查找表 B 中不存在的所有 id,然后将它们插入。

INSERT INTO TableB (TableAId , Name)
SELECT Id,Name FROM TableA as tableA
WHERE not exists( ...)

但是,这带来了一个问题。用户可以随时从 TableB 中删除某些内容,因此如果用户删除了一行,然后另一个用户出现,或者甚至同一个用户出现并对表 A 执行某些操作,我的存储过程将在表 B 中恢复删除的行。因为它仍然存在于表 A 而不是表 B 中,因此满足存储过程条件。

那么有没有更好的方法来处理使用批量插入时需要更新的两个表?

【问题讨论】:

  • 我很确定 RDMS 的全部意义在于避免在有多个并发连接时出现互斥和更新问题。我不是数据库专家,也不是在电视上播放,但据我所知,您可以使用一些构造来使查询“原子化”。
  • @San Jacinto:正确,但 SQLBulkCopy 是一个并发症。即使这样,后面的写入也无法区分哪些行是他们的,哪些是之前的写入,在 B 中有间隙。

标签: sql sql-server sqlbulkcopy


【解决方案1】:

SQLBulkCopy 使这变得复杂,所以我会考虑使用临时表和OUTPUT clause

示例,混合使用客户端伪代码和 SQL

create SQLConnection

Create #temptable
Bulkcopy to #temptable

Call proc on same SQLConnection

proc:
   INSERT tableA (..)
   OUTPUT INSERTED.key, .. INTO TableB
   SELECT .. FROM #temptable

close connection

注意事项:

  • temptable 将是本地连接并被隔离

  • 对 A 和 B 的写入将是原子的
  • 重叠或以后的写入并不关心 A 和 B 以后会发生什么
  • 强调最后一点,A 和 B 只会从 #temptable 中的行集填充

替代方案:

向 A 和 B 添加另一个名为 sessionid 的列,并使用它来识别行批次。

【讨论】:

    【解决方案2】:

    一种选择是使用 SQL Server 输出子句:

    INSERT YourTable (name)
    OUTPUT INSERTED.*
    VALUES ('NewName')
    

    这会将插入行的id, name返回给客户端,因此您可以在第二个表的插入操作中使用它们。

    【讨论】:

      【解决方案3】:

      作为替代解决方案,您可以使用database triggers 更新第二个表。

      【讨论】:

      猜你喜欢
      • 2022-08-11
      • 2019-09-20
      • 1970-01-01
      • 1970-01-01
      • 2015-05-15
      • 2020-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多