我的存储过程中有如下语句:
IF (
SELECT COUNT(1)
FROM dbo.t_user_suggested
WHERE ListId = @pListId
) > 0
BEGIN
DELETE
FROM dbo.t_user_suggested
WHERE ListId = @pListId
END
INSERT INTO dbo.t_user_suggested (
Id
,InId
,InName
,UserId
,ListId
)
SELECT DISTINCT Id
,InId
,InName
,@pUserId
,@pListId
FROM CTE123
我收到错误违反 PRIMARY KEY 约束“PK_t_user_suggested”。无法在对象“dbo.t_user_suggested”中插入重复键。在插入之前,我有一个明确的检查以删除所有记录,并且此错误是随机出现的。我手动执行了 10-15 次存储过程,没有出现错误。在我的存储过程中控制移动到插入之前,如何确保删除所有记录。
答案 0 :(得分:2)
如果两个事务同时运行此代码,它们都可以尝试插入相同的密钥。在默认的锁定/隔离级别下,没有什么可以阻止它们,而且您似乎并没有使用事务。
最好的办法是使用带有正确提示的交易。
<块引用>顺便说一下,不需要 IF (SELECT COUNT(1)...
,因为 DELETE
只会删除存在的行。另外,如果你真的需要这个,那么你应该使用 IF(EXISTS
代替
SET XACT_ABORT, NOCOUNT ON;
BEGIN TRAN;
DELETE
FROM dbo.t_user_suggested WITH (HOLDLOCK)
WHERE ListId = @pListId;
INSERT INTO dbo.t_user_suggested (
Id
,InId
,InName
,UserId
,ListId
)
SELECT DISTINCT Id
,InId
,InName
,@pUserId
,@pListId
FROM CTE123;
COMMIT TRAN;
或者,如果 @pListId
实际上是主键,那么发出一个 UPDATE
会更好
UPDATE
SET Id = CTE123.InId
,InId = CTE123.InId
,InName = CTE123.InName
,UserId = CTE123.UserId
FROM dbo.t_user_suggested t
JOIN (
SELECT DISTINCT Id
,InId
,InName
,@pUserId AS pUserId
,@pListId AS pListId
FROM CTE123
) CTE123 ON CTE123.pListId = t.pListId
WHERE t.ListId = @pListId;
答案 1 :(得分:0)
我怀疑下面的查询返回了不止一行。因此,您会为每一行获得相同的 ListID。
SELECT DISTINCT Id
,InId
,InName
,@pUserId
,@pListId
FROM CTE123
请尝试执行以下查询:
IF (
SELECT COUNT(1)
FROM dbo.t_user_suggested
WHERE ListId = @pListId
) > 0
BEGIN
DELETE
FROM dbo.t_user_suggested
WHERE ListId = @pListId
END
INSERT INTO dbo.t_user_suggested (
Id
,InId
,InName
,UserId
,ListId
)
SELECT top 1 DISTINCT Id
,InId
,InName
,@pUserId
,@pListId
FROM CTE123
我已尝试创建您的情况,并且您的查询工作正常。您可以查看以下示例。 ListId
不是您的主键列,或者您的选择查询返回多行。
DB-小提琴:
表定义和插入语句:
create table t_user_suggested (Id int ,InId int,InName varchar(50),UserId INT,ListId INT);
INSERT INTO t_user_suggested values(1,1,'A',2,3);
选择查询:
select* from t_user_suggested
表的当前输出:
Id | InId | InName | UserId | ListId |
---|---|---|---|---|
1 | 1 | A | 2 | 3 |
您的查询:
删除部分
IF (
SELECT COUNT(1)
FROM dbo.t_user_suggested
WHERE ListId = 3
) 0
BEGIN
DELETE
FROM dbo.t_user_suggested
WHERE ListId = 3
END
删除后选择查询:
select * from t_user_suggested;
输出:
Id | InId | InName | UserId | ListId |
---|
已成功删除行。
插入语句:
INSERT INTO dbo.t_user_suggested (
Id
,InId
,InName
,UserId
,ListId
)
values(1,1,'A',2,3);
插入后选择查询:
select * from t_user_suggested;
输出:
Id | InId | InName | UserId | ListId |
---|---|---|---|---|
1 | 1 | A | 2 | 3 |
db
答案 2 :(得分:0)
我不确定到底是什么问题,但似乎是竞争条件或事务锁定/隔离级别的问题。我暂时使用了 MERGE 语句而不是插入和删除来解决问题。所以下面是我的查询。
MERGE t_user_suggested AS tar
USING CTE123 AS cte
ON tar.Id = cte.Id
AND tar.InId = cte.InId
AND tar.ListId = @pListId
WHEN NOT MATCHED BY Target
THEN
INSERT (
Id
,InId
,InName
,UserId
,ListId
)
VALUES (
cte.Id
,cte.IngrId
,cte.InName
,@pUserId
,@pListId
)
-- For Updates
WHEN MATCHED THEN UPDATE SET
tar.IName = cte.InName,
tar.datetimelastseen = null,
tar.seenlast24hours=null
-- For Deletes
WHEN NOT MATCHED BY SOURCE THEN
DELETE;