Sql 如何设置一条记录标记为1,其他所有记录标记为0

Sql 如何设置一条记录标记为1,其他所有记录标记为0,sql,sql-server,Sql,Sql Server,我有一个表地址,列ID为PK、EmpID为int、地址为nvarchar100、IsDefault位。 现在我必须确保只有一个具有相同EmpID的记录IsDefault设置为1。 我现在已经完成了触发器的跟踪。 第一个是插入触发器。首先,它检查IsDefault中是否输入了值1。如果是,则检查是否有多条记录的EmpID和IsDefault值设置为1。如果这也是真的,那么它会将同一EmpID的所有其他IsDefault值设置为0: 另一个是更新触发器,我不知道如何编写它。首先,它执行与插入触发器相

我有一个表地址,列ID为PK、EmpID为int、地址为nvarchar100、IsDefault位。 现在我必须确保只有一个具有相同EmpID的记录IsDefault设置为1。 我现在已经完成了触发器的跟踪。 第一个是插入触发器。首先,它检查IsDefault中是否输入了值1。如果是,则检查是否有多条记录的EmpID和IsDefault值设置为1。如果这也是真的,那么它会将同一EmpID的所有其他IsDefault值设置为0:

另一个是更新触发器,我不知道如何编写它。首先,它执行与插入触发器相同的操作,检查插入值是否为1,其中值为0。如果是,如果有多条记录具有相同的EmpID,并且IsDefault设置为1。如果是

如何写入将同一EmpID的所有其他记录设置为0,而正在更新的记录保持为1

create trigger [dbo].[TRG_dbo_Addresses_IsDefault_OnlyOneRecord_update]
   on [dbo].[Addresses] 
   after update 
as 
begin

    set nocount on;

    begin try

        if exists (
            select *
            from inserted as i
            inner join deleted as d on d.ID=i.ID
            where i.IsDefault = 1
                and d.IsDefault = 0)
        begin
            if (
                select count(*)
                from dbo.Addresses as lao
                inner join inserted as i on i.ID=lao.ID
                where lao.IsDefault = 1
                    and lao.EmpID = i.EmpID
                ) > 1 
            begin
                update lao
                set lao.IsDefault = 0
                from dbo.Addresses as lao
                inner join inserted as i on i.ID=lao.ID
                where (I don't have an idea what to put here)
                    and lao.OrganisationID = i.OrganisationID
            end
        end
    end try

    begin catch

        if @@trancount > 0
            rollback tran;

    end catch

end

我正在研究MS SQL 2016。< /P> < P>我可以考虑一下,如果没有触发器,你要解决的问题是否可以解决。触发器往往会带来显著的性能损失,并且会将逻辑与代码的其余部分分开,这使得在将来维护它成为一件令人头痛的事情


如果您真的想在行插入/更新时使用触发器解决方案,并且始终有一行用位标记,那么不要尝试使用它计算行数。只需将相关EmpID的所有行设置为0,然后在触发器中将插入的行更新为1。

我同意Matt的观点:如果可能,避免触发

无论如何,我认为在更新触发器中,您应该更改为:

         if (
            select count(*)
            from dbo.Addresses as lao
            inner join inserted as i on lao.EmpID = i.EmpID
            where lao.IsDefault = 1                     
            ) > 1 
        begin
            update lao
            set lao.IsDefault = 0
            from dbo.Addresses as lao
            inner join inserted as i on lao.EmpID = i.EmpID
            where  lao.IsDefault = 1
                and lao.ID <> i.id
        end
此外,您可以将其改写为:

IF EXISTS(SELECT 1 FROM 
          FROM dbo.Addresses as lao 
          INNER join inserted as i on lao.EmpID = i.EmpID
          WHERE lao.IsDefault = 1   AND lao.ID <>i.ID)           
          BEGIN
                UPDATE lao
                SET lao.IsDefault = 0
                FROM dbo.Addresses as lao
                INNER JOIN inserted as i on lao.EmpID = i.EmpID
                WHERE lao.IsDefault = 1
                    and lao.ID <> i.id
          END
您也应该更改插入触发器

更新:插入触发器。 就我所见,但我不能做测试,所以请做完整的案例测试,如果ID总是最大值,或者如果您想保留上次插入的ID的默认值,我想您可以如下重写您的插入触发器:您可以删除if-too,如果您不关心总是对零行进行更新的话

as 
begin    
    set nocount on;    
    begin try
       IF EXISTS(SELECT 1  
          FROM dbo.Addresses as lao 
          INNER join inserted as i on lao.EmpID = i.EmpID
          WHERE lao.IsDefault = 1 
                AND lao.ID <>i.ID
                AND i.IsDefault=1)           
          BEGIN
                UPDATE lao
                SET lao.IsDefault = 0
                FROM dbo.Addresses as lao
                INNER JOIN inserted as i on lao.EmpID = i.EmpID
                WHERE lao.IsDefault = 1
                    and lao.ID <> i.id
                    AND i.IsDefault=1
          END
end try
begin catch
    if @@trancount > 0
        rollback tran;
end catch

此更改和i.IsDefault=1也可应用于更新触发器。

此处所需的行为是什么?是否有其他默认值像您当前实现的那样神奇地设置为0,或者每个empid最多可以将一行设置为1?如果是后者,并且产生错误而不是更改其他数据是可以接受的,则可以通过过滤索引来实现。@damien the Insiever:每个EmpID都有一条记录。我可以在一个表中有多个EmpID,但只有一个可以将IsDefault设置为1。所有其他值必须为0。可以更改同一EmpID的默认地址。所以我不能使用索引,因为我希望能够为相同的EmpID在其他地址上更改IsDefault值。所以你想神奇地更改其他行的行为吗?因为很明显,如果您先取消设置当前默认值,然后再设置新的defaultyes,索引工作正常。我希望它得到改变。如果有任何其他方式,然后触发,我在这里听。我在想,没有触发器是不可能做到这一点的。正如我对马特的回答:如果有任何其他方法,那么触发器,让我知道。我也不喜欢触发器,但是没有触发器我无法找到如何操作,因为我必须在更新时更改字段中的值。如果你能告诉我,我的插入触发器有什么问题?或者你的意思是,如果存在,最好将其重写为?我认为你应该删除I.ID=lao.ID上的insert触发器,并使用与我为UPDATE触发器编写的相同的值,然后你可以选择使用COUNT或exists,但我认为应该修改join子句。你插入的列ID总是更高的值?是的。ID列始终较高。这是一个身份1,1。
as 
begin    
    set nocount on;    
    begin try
       IF EXISTS(SELECT 1  
          FROM dbo.Addresses as lao 
          INNER join inserted as i on lao.EmpID = i.EmpID
          WHERE lao.IsDefault = 1 
                AND lao.ID <>i.ID
                AND i.IsDefault=1)           
          BEGIN
                UPDATE lao
                SET lao.IsDefault = 0
                FROM dbo.Addresses as lao
                INNER JOIN inserted as i on lao.EmpID = i.EmpID
                WHERE lao.IsDefault = 1
                    and lao.ID <> i.id
                    AND i.IsDefault=1
          END
end try
begin catch
    if @@trancount > 0
        rollback tran;
end catch