解决大规模更新时的复合键冲突

时间:2013-08-29 17:15:11

标签: sql sql-server

假设我有一个包含字段ManagersId的表Name。另一个表Accounts包含字段IdName。这两个表的关系在多对多表ManagedAccounts中定义,其复合键为ManagerIdAccountId。因此,您可以在某个帐户中拥有多个经理,但该帐户上不能有多个相同的经理。

现在,我有一个名为MergeAccounts的存储过程,它以逗号分隔的varchar的形式接收Manager Id和Manager ID列表。它目前看起来很像这样:

create procedure MergeAccounts @managerId nvarchar(12), @mergedManagers nvarchar(max) as declare @reassignment nvarchar(max)

set @reassignment='update ManagedAccounts set ManagerId='+@managerId+' where ManagerId in ('+@mergedManagers+')'

exec sp_executesql @reassignment

由于两个经理可能在同一个帐户上,它会给我一个错误,说我违反了我在该表上的复合键。如何构建我的代码以简单地删除任何冗余行而不考虑订单?

1 个答案:

答案 0 :(得分:1)

更改动态SQL以首先删除任何潜在的冲突。然后进行更新。在交易中包装所有内容。

(顺便说一下,我会通过创建一个从逗号分隔的列表中返回一个表的表值函数来完全避免使用动态SQL ...这非常有用,你可以找到一个像你已编写过的函数谷歌吧)

set @reassignment='
BEGIN TRAN;

BEGIN TRY
    DELETE  m1
    FROM    ManagedAccounts m1
            JOIN ManagedAccounts m2 ON m1.AccountId = m2.AccountId
    WHERE   m2.ManagerId = ' + @managerId + '
            AND m1.ManagerId IN (' + @mergedAccounts + ')

    UPDATE ManagedAccounts SET ManagerId=' + @managerId + ' WHERE ManagerId IN (' + @mergedManagers + ')
    COMMIT;
END TRY
BEGIN CATCH
    ROLLBACK;
END CATCH;';