插入更新重复值SQL

时间:2016-02-19 02:19:32

标签: sql sql-server sql-server-2008 stored-procedures

我有这个存储过程:

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中阻止此操作?

谢谢。

2 个答案:

答案 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 existsINSERT可能会失败,您的代码应该能够处理这种情况。

您似乎很乐意压制/忽略错误。在这种情况下,简单的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值调用它,则只有一个会实际插入该值,而第二个会默默地失败并且不执行任何操作。来电者不会知道这次碰撞。在你的情况下,这是可以接受的。