Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用触发器SQL防止重复_Sql_Sql Server_Tsql - Fatal编程技术网

使用触发器SQL防止重复

使用触发器SQL防止重复,sql,sql-server,tsql,Sql,Sql Server,Tsql,我的目标是插入第一个插入,但不要让第二个通过,因为NIC是重复的。我不知道为什么,但它不会让第一个通过而没有其他NIC进行比较,如果它已经存在一个相等的 我知道我可以使用“唯一”来防止重复,但我尝试使用触发器:/ Create table Utentes ( numUtente nchar(3), Name nchar(40) not null, NIC nchar(8) not null, Constraint PK_Utente Primary Key(num

我的目标是插入第一个插入,但不要让第二个通过,因为NIC是重复的。我不知道为什么,但它不会让第一个通过而没有其他NIC进行比较,如果它已经存在一个相等的

我知道我可以使用“唯一”来防止重复,但我尝试使用触发器:/

Create table Utentes
(
    numUtente nchar(3),
    Name nchar(40) not null,
    NIC nchar(8) not null,
    Constraint PK_Utente Primary Key(numUtente)
)


create trigger tr_Duplicate 
on Utentes 
after insert 
as
    declare @NIC nchar(8)

    select @NIC = NIC from inserted

    if exists(select * from Utentes where NIC = @NIC)
    begin
        print 'NIC already in database'
        rollback
    end
go


insert into Utentes (numUtente, Name, NIC) 
values ('123', 'asd', '12345678')

insert into Utentes (numUtente, Name, NIC) 
values ('124', 'asd', '12345678')

select * from Utentes
结果:

NIC已在数据库中
Msg 3609,第16级,状态1,第1392行
事务在触发器中结束。批处理已中止


您应该真正使用约束。“插入后”触发器实际上会将第二行放入表中。希望没有人使用
NOLOCK
来阅读它

在任何情况下,都必须实际计算行数并查找多个实例。应该是这样的:

Create trigger tr_Duplicate on Utentes after INSERT as
begin    
    if exists (select 1
               from utentes u join
                    inserted i
                    on u.nic = i.nic
               group by u.nic
               having count(*) > 1
              )
    begin
        print 'NIC already in database';
        rollback;
    end;
end;
使用
而不是
触发器,如果表中已有新行,则不会向表中添加新行:

create trigger tr_Duplicate on Utentes after INSERT as
begin    
    if exists (select 1
               from utentes u join
                    inserted i
                    on u.nic = i.nic
              )
    begin
        print 'NIC already in database';
        rollback;
    end;
    else
    begin
        insert into utentes
            select i.*
            from inserted i;
    end;
end;

您应该真正使用约束。“插入后”触发器实际上会将第二行放入表中。希望没有人使用
NOLOCK
来阅读它

在任何情况下,都必须实际计算行数并查找多个实例。应该是这样的:

Create trigger tr_Duplicate on Utentes after INSERT as
begin    
    if exists (select 1
               from utentes u join
                    inserted i
                    on u.nic = i.nic
               group by u.nic
               having count(*) > 1
              )
    begin
        print 'NIC already in database';
        rollback;
    end;
end;
使用
而不是
触发器,如果表中已有新行,则不会向表中添加新行:

create trigger tr_Duplicate on Utentes after INSERT as
begin    
    if exists (select 1
               from utentes u join
                    inserted i
                    on u.nic = i.nic
              )
    begin
        print 'NIC already in database';
        rollback;
    end;
    else
    begin
        insert into utentes
            select i.*
            from inserted i;
    end;
end;

我支持反对使用触发器的观点,并建议使用独特的约束。依我的拙见,我宁愿在ETL层中寻找解决方案,在插入记录时对其进行分组。使用触发器,您将遇到上述并发性和一致性问题,如果表变得足够大,需要花费一些时间来处理,则可能会导致tempdb或T-log膨胀。

。依我的拙见,我宁愿在ETL层中寻找解决方案,在插入记录时对其进行分组。使用触发器,您将遇到上述并发性和一致性问题,如果表变得足够大,需要花费一些时间来处理,则可能会导致tempdb或T-log膨胀。

inserted
是一个集合,不一定只是一条记录。因此,您的
选择@NIC=NIC from inserted
可能会失败或行为与您想象的不同。为什么要拒绝第一个?这是第一张放进去的唱片,所以肯定没有复制品。我想成为第一张被接受的唱片,因为没有其他唱片。但它甚至不会让第一个触发。你的触发器是后插入触发器。因此,当它到达触发器中的代码时,您应该认为触发触发器的行已经插入到表中。
inserted
是一个集合,不一定只是一条记录。因此,您的
选择@NIC=NIC from inserted
可能会失败或行为与您想象的不同。为什么要拒绝第一个?这是第一张放进去的唱片,所以肯定没有复制品。我想成为第一张被接受的唱片,因为没有其他唱片。但它甚至不会让第一个触发。你的触发器是后插入触发器。因此,当它到达触发器中的代码时,应该预期导致触发器触发的行已经插入到表中。