我有这个存储过程:
alter procedure spGroupInsert
(@Group varchar(5))
as
if not exists (select * from tbGroup where Group = @Group)
begin
insert into tbGroup(Group)
values(@Group)
end
else
begin
waitfor delay '00:00:01'
end
存储过程旨在防止tbGroup
上的重复。接下来,我需要一个UPDATE
存储过程:
alter procedure spGroupUpdate
(@GroupID int, @Group varchar(5))
as
begin
update tbGroup
set Group = @Group
where GroupID = @GroupID
end
表格应为:
GroupID Group
1 A
2 B
3 C
4 D
ff.
GroupID
是身份。对于插入SP,我确信不会有问题。
但是,如果我执行Update存储过程,那么我会更改Group
。这将是重复的。例如,如果我将A组更新为B.那么它将复制B。
如何在更新存储过程中在T-SQL中阻止此操作?
谢谢。
答案 0 :(得分:1)
ALTER TABLE tbGroup
ADD CONSTRAINT UC_Group UNIQUE (Group);
这将在更新存储过程中处理。当存在具有相同组
的现有行时,它不会更新alter procedure spGroupUpdate
(@GroupID int, @Group varchar(5))
as
begin
update tbGroup
set Group = @Group
WHERE GroupID = @GroupID
AND NOT EXISTS
(
SELECT *
FROM tbGroup x
WHERE x.GroupID <> @GroupID
AND x.Group = @Group
)
end
答案 1 :(得分:1)
您说spGroupInsert
您确定不会出现问题。实际上,存在一个问题。
此程序不保证您永远不会插入副本。如果两个会话试图同时插入相同的值,则可以轻松获得重复项。
两个会话都可以同时进行if not exists
检查,两者都可以继续INSERT
。
alter procedure spGroupInsert
(@Group varchar(5))
as
if not exists (select * from tbGroup where Group = @Group)
begin
insert into tbGroup(Group)values(@Group)
end
else
begin
waitfor delay '00:00:01'
end
保证Group
值唯一的唯一方法是创建一个唯一约束,通常将其作为唯一索引实现。
CREATE UNIQUE NONCLUSTERED INDEX [IX_Group] ON [dbo].[tbGroup]
(
[Group] ASC
)
GO
如果有这样的唯一索引,上面示例中的一个会话将无法INSERT
重复,并且存储过程的调用者将收到有关唯一约束违规的错误消息。调用者需要决定如何处理此错误,如何处理它。
检查if not exists
可以减少出现此错误的可能性,但无法完全阻止此错误。因此,使用支票if not exists
或不支票if not exists
,INSERT
可能会失败,您的代码应该能够处理这种情况。
您似乎很乐意压制/忽略错误。在这种情况下,简单的TRY ... CATCH
就足够了。
alter procedure spGroupInsert
(@Group varchar(5))
as
BEGIN
SET NOCOUNT ON; SET XACT_ABORT ON;
BEGIN TRANSACTION;
BEGIN TRY
if not exists (select * from tbGroup where Group = @Group)
begin
insert into tbGroup(Group)values(@Group);
end
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION;
END CATCH;
END
使用此存储过程(和唯一索引),如果两个会话尝试同时使用相同的Group
值调用它,则只有一个会实际插入该值,而第二个会默默地失败并且不执行任何操作。来电者不会知道这次碰撞。在你的情况下,这是可以接受的。