【问题标题】:Trigger to prevent Insertion for duplicate data of two columns防止插入两列重复数据的触发器
【发布时间】:2013-08-29 05:18:23
【问题描述】:

我正在处理SQL Server 2008R2,我有以下表格

ID     Name     date
 1     XYZ      2010
 2     ABC      2011
 3     VBL      2010

现在我想阻止插入,如果我有一个数据,虽然 ID 不同但数据存在

 ID    Name     date
  4    ABC      2011

请指导我如何编写此触发器。

【问题讨论】:

  • 您真的需要触发器吗?您是否尝试过唯一索引或约束?
  • 当我的主键是ID时如何申请??
  • 在 xxTable 上创建唯一的非聚集索引 XXTable_Unq(名称 ASC,[日期] ASC)
  • 允许你使用这个sql插入:insert into tb(name,date)select 'ABC',2048 from dual where not exists (select from tb where name='ABC')

标签: sql sql-server sql-server-2008


【解决方案1】:

类似这样的:

CREATE TRIGGER MyTrigger ON dbo.MyTable
AFTER INSERT
AS

if exists ( select * from table t 
    inner join inserted i on i.name=t.name and i.date=t.date and i.id <> t.id)
begin
    rollback
    RAISERROR ('Duplicate Data', 16, 1);
end
go

这只是插入,您可能也需要考虑更新。

更新

一种更简单的方法是在表上创建一个唯一约束,这也将强制它进行更新并消除对触发器的需求。做吧:

ALTER TABLE [dbo].[TableName]    
ADD CONSTRAINT [UQ_ID_Name_Date] UNIQUE NONCLUSTERED
(
    [Name], [Date]
)

然后你就可以做生意了。

【讨论】:

  • 虽然这会引发错误但无法停止插入,但我的问题仍然存在
  • 哦,是的,那是因为我错过了 ROLLBACK 行 - 所以像我刚才那样添加那个。但是看看詹姆斯的回答,也许你所追求的是一个独特的约束。
  • 如果您需要使用触发方法(例如,因为您需要自定义错误消息),您还需要检查您是否意外加入了与刚刚插入的相同记录。在我将“i.id t.id”的等效项添加到 on 子句之前,我一直在寻找重复项。
  • 唯一约束的问题可能是它的最大长度(900B)
  • 在我的例子中,一个唯一的键会破坏大量正在运行的作业和存储过程的平衡。我只是希望所有这些都能正常进行,但要避免插入而不会引发错误。很多用例。
【解决方案2】:

如果您使用存储过程将数据插入表中,则实际上不需要触发器。您首先检查组合是否存在然后不要插入。

CREATE PROCEDURE usp_InsertData
@Name varchar(50),
@Date DateTime
AS
BEGIN

IF (SELECT COUNT(*) FROM tblData WHERE Name = @Name AND Date=@Date) = 0
    BEGIN
        INSERT INTO tblData
                    ( Name, Date)
             VALUES (@Name, @Date)
        Print 'Data now added.'
     END
ELSE
    BEGIN
        Print 'Dah! already exists';
    END
END

如果您不通过存储过程插入数据,则可以使用以下触发器。

CREATE TRIGGER checkDuplicate ON tblData
AFTER INSERT
AS

IF EXISTS ( SELECT * FROM tblData A 
INNER JOIN inserted B ON B.name=A.name and A.Date=B.Date)
BEGIN
    RAISERROR ('Dah! already exists', 16, 1);
END
GO  

【讨论】:

  • 触发器报错但数据还在插入表中,如何停止插入数据
【解决方案3】:

您实际上并不需要触发器。只需为多个列设置唯一约束即可。

ALTER TABLE [dbo].[TableName]    
ADD CONSTRAINT [UQ_ID_Name_Date] UNIQUE NONCLUSTERED
(
    [ID], [Name], [Date]
)

【讨论】:

  • 约束不应该只在名称和日期列上吗?
【解决方案4】:

还有一个选择,使用 insert 代替 触发器。

CREATE TRIGGER MyTrigger ON dbo.MyTable
INSTEAD OF INSERT
AS

if not exists (
    select *
    from MyTable t 
    inner join inserted i
       on i.name=t.name
       and i.date=t.date and i.id <> t.id )
begin
    Insert into MyTable (Name, Date) Select Name, Date from inserted
end
go

这是一个很好的 discussion 说明如何以及何时使用它们。

【讨论】:

    【解决方案5】:

    这个答案的灵感来自于 20 年 4 月 13 日 18:34。

    CREATE TRIGGER MyTrigger ON dbo.MyTable  
    INSTEAD OF INSERT  
    AS  
    
    if not exists (  
        select * from MyTable t   
        inner join inserted i
        on i.name=t.name and i.date=t.date and i.id <> t.id )  
    begin  
        Insert into MyTable (Name, Date) Select Name, Date from inserted  
    end  
    else  
        THROW 51000, 'Statement terminated because a duplicate was found for the object', 1;      
    go  
    

    【讨论】:

      【解决方案6】:

      试试这个

       CREATE TRIGGER trg ON TableName
       AFTER INSERT 
       AS
        Begin
        Declare @id int,@name varchar(10),@date DateTime
        Declare @cnt1 int,@cnt2 int,@cnt3 int
      
        INSERT INTO TableName(ID, Name, Date) VALUES(4,'ABC',2011)
        select @id=ID,@name=Name,@date=Date from inserted
      
        select @cnt2=Count(*) from TableName where Name=@name
        select @cnt3=Count(*) from TableName where Date=@date
      
        if(@cnt2>1 or @cnt3>1)
          Rollback
        else 
          Commit
      
        end
      

      【讨论】:

      • 这充满了错误,无法正常工作。您的插入语句具有硬编码值,而且它不允许具有重复名称或日期甚至 ID 的数据。
      • 要求是不允许重复甚至不同的id,对吧?
      猜你喜欢
      • 2021-04-05
      • 2021-09-25
      • 1970-01-01
      • 2017-04-26
      • 1970-01-01
      • 2011-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多