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

时间:2017-09-12 08:14:00

标签: sql sql-server

我有table AddressesID (PK), EmpID (int), Address (nvarchar(100), IsDefault (bit)。 现在我必须确保只有一个具有相同EmpID的记录将IsDefault设置为1。 我现在已经完成了触发器的操作。 第一个是插入触发器。首先,检查IsDefault中是否输入了值1。如果是,那么它检查是否有多个记录在1上设置了相同的EmpIDIsDefault值。如果这也是真的,则它为所有其他IsDefault值设置相同EmpID到0.:

create trigger [dbo].[TRG_dbo_Addresses_IsDefault_OnlyOneRecord_insert]
   on [dbo].[lAddressesOrganisations] 
   after insert 
as 
begin

    set nocount on;

    begin try

        if exists (
            select *
            from inserted as i
            where i.IsDefault = 1)
        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
                where (
                    select row_number () over (partition by EmpID order by ID desc) as rn
                    from dbo.Addresses as lao
                ) > 1
            end
        end
    end try

    begin catch

        if @@trancount > 0
            rollback tran;

    end catch

end

另一个是更新触发器,我不知道如何编写它。首先它与插入触发器相同,检查插入的值是1,其中值为0.如果是,如果有多个记录,同一EmpIDIsDefault设置为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。

2 个答案:

答案 0 :(得分:1)

我同意马特:如果可能,请避免触发。

无论如何,我认为在你的UPDATE触发器中你应该改为:

         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

Morevore,您可以将其重写为:

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,如果你不关心总是为零行做一个UPDATE)

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

此更改(AND i.IsDefault = 1)也可以应用于UPDATE触发器。

答案 1 :(得分:0)

我可能会考虑您在这里尝试解决的问题是否可以在没有触发器的情况下解决。触发器往往会带来显着的性能损失,并且可以将逻辑与代码的其余部分分开,这使得将来维护成为一个令人头痛的问题。

如果你真的想在行插入/更新上使用触发器解决方案,并且总是只有1行标记了该位,请不要尝试用它来计算行数。只需将相关EmpID的所有行设置为0,然后在触发器中将插入的行更新为1.