sql server trigger是否有执行顺序?

时间:2017-04-10 21:17:06

标签: sql-server tsql

我使用多个触发器在Sqlserver中使用trigger实现backward date scheduling

但是这里发生了一些有线的事情。这是我注意到的

  • AFTER INSERT以下三个字段已更新SHIP BY,A-MOUNT BY,A-POWDER BY
  • 当我将某些内容更改为同一记录并保存A-FAB已更新
  • 第二次将某些内容更改为同一记录并保存A-C\S, A-PRINT BY已更新

我必须更新3次以更新所有字段

以下是后向调度的逻辑。所有字段都是相互关联的

  

SHIP BY = CUSTOMER PROMISED DATE-1

     

A-MOUNT BY = SHIP BY -1

     

A-POWDER BY = A-MOUNT BY-1或A-POWDER BY也相等于日期-2

     

A-FAB BY = A-POWDER BY - 1或A-FAB BY也相等于日期-3

     

A-C / S BY = A-FAB BY或A-C / S BY也按日期等于-4

     

A-CUT BY = A-C / S BY -1或A-CUT BY也等于日期-5

/****** Object:  Trigger [dbo].[CALC-PROMISED-DATE-AND-SHIPBY]    Script Date: 4/6/2017 2:46:01 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[CALC-PROMISED-DATE-AND-SHIPBY] 
    ON [dbo].[WORKORDERS]
    AFTER  INSERT, UPDATE
    AS 
    BEGIN
    set nocount on
     IF TRIGGER_NESTLEVEL() > 1
     RETURN
     set datefirst 7;
UPDATE T1
    [SHIP BY] = 
              CASE datepart(WEEKDAY, t1.[CALC PROMISED DATE])
                    WHEN 1 then DateAdd( day, -2, t1.[CALC PROMISED DATE])
                    WHEN 7 then DateAdd( day, -1, t1.[CALC PROMISED DATE])
                ELSE
                    CASE 
                        WHEN t1.[RE-COMMIT DATE] =Null THEN ISNULL(T1.[PROMISED DATE],Null)
                         WHEN t1.[RE-COMMIT DATE] is null THEN ISNULL(T1.[PROMISED DATE],Null)
                    ELSE ISNULL(T1.[RE-COMMIT DATE],Null)
                    END
            END       

            FROM WORKORDERS T1
                 INNER JOIN inserted i ON T1.[WORK ORDER #] = i.[WORK ORDER #]
                END

A-MOUNT BY

    /****** Object:  Trigger [dbo].[MOUNTBY]    Script Date: 4/6/2017 2:46:54 PM ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    ALTER TRIGGER [dbo].[MOUNTBY] 
        ON [dbo].[WORKORDERS]
        AFTER  INSERT,UPDATE
        AS 
        BEGIN
         IF TRIGGER_NESTLEVEL() > 1
         RETURN
         set datefirst 7;
    UPDATE T1 
        [A-MOUNT BY] = 
        case       datepart(WEEKDAY,  DateAdd(day,-1,t1.[SHIP BY]))
             when 7 then DateAdd( day, -2, t1.[SHIP BY] )
             when 1 then DateAdd( day, -3, t1.[SHIP BY] )
            else   DateAdd( day, -1, t1.[SHIP BY] )--t1.[A-C/S BY]-1
        END
FROM WORKORDERS T1
     INNER JOIN inserted i ON T1.[WORK ORDER #] = i.[WORK ORDER #]
    END

A-POWDER BY

   /****** Object:  Trigger [dbo].[POWDERBY]    Script Date: 4/6/2017 2:49:53 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[POWDERBY] 
    ON [dbo].[WORKORDERS]
    AFTER INSERT,UPDATE
    AS 
    BEGIN
     IF TRIGGER_NESTLEVEL() > 1
     RETURN
     set datefirst 7;
UPDATE T1 
--SET
SET [A-POWDER BY] = 
case datepart(WEEKDAY, t1.[A-MOUNT BY]-1 )
      when 7 then DateAdd( day, -2, t1.[A-MOUNT BY] )
     when 1 then DateAdd( day, -3, t1.[A-MOUNT BY])
    else  t1.[A-MOUNT BY]-1 
END

FROM WORKORDERS T1
     INNER JOIN inserted i ON T1.[WORK ORDER #] = i.[WORK ORDER #]
    END

A-FAB BY

   /****** Object:  Trigger [dbo].[FABBY]    Script Date: 4/6/2017 2:50:23 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[FABBY] 
    ON [dbo].[WORKORDERS]
    AFTER insert, UPDATE
    AS 
    BEGIN
     IF TRIGGER_NESTLEVEL() > 1
     RETURN
     set datefirst 7;
UPDATE T1 
SET [A-FAB BY] =  case datepart(WEEKDAY, t1.[A-POWDER BY]-1 )
      when 7 then DateAdd( day, -2, t1.[A-POWDER BY] )
     when 1 then DateAdd( day, -3, t1.[A-POWDER BY])
    else  t1.[A-POWDER BY]-1 
END
FROM WORKORDERS T1
     INNER JOIN inserted i ON T1.[WORK ORDER #] = i.[WORK ORDER #]
    END

a-PRINT BY

   /****** Object:  Trigger [dbo].[PRINTBY]    Script Date: 4/6/2017 2:50:50 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[PRINTBY] 
    ON [dbo].[WORKORDERS]
    AFTER INSERT, UPDATE
    AS 
    BEGIN
     IF TRIGGER_NESTLEVEL() > 1
     RETURN
     set datefirst 7;
UPDATE T1
SET [A-PRINT BY] = case datepart(WEEKDAY, t1.[A-FAB BY] )
      when 7 then DateAdd( day, -2, t1.[A-FAB BY])
     when 1 then DateAdd( day, -3, t1.[A-FAB BY])
    else  t1.[A-FAB BY]-1 
END
FROM WORKORDERS T1
     INNER JOIN inserted i ON T1.[WORK ORDER #] = i.[WORK ORDER #]
    END

A-C / S BY

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[C/SBY] 
    ON [dbo].[WORKORDERS]
    AFTER  INSERT,UPDATE
    AS 
    BEGIN
     IF TRIGGER_NESTLEVEL() > 1
     RETURN
     set datefirst 7;
UPDATE T1 
--SET
SET [A-C/S BY] =  case datepart(WEEKDAY, t1.[A-PRINT BY]-1 )
      when 7 then DateAdd( day, -2, t1.[A-PRINT BY] )
     when 1 then DateAdd( day, -3, t1.[A-PRINT BY])
    else  t1.[A-PRINT BY]-1 
END
FROM WORKORDERS T1
     INNER JOIN inserted i ON T1.[WORK ORDER #] = i.[WORK ORDER #]
    END

A-CUT BY

  SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[CUTBY] 
    ON [dbo].[WORKORDERS]
    AFTER INSERT, UPDATE
    AS 
    BEGIN
     IF TRIGGER_NESTLEVEL() > 1
     RETURN
     set datefirst 7;
UPDATE T1 
--SET
SET [A-CUT BY] = 
case       datepart(WEEKDAY,  DateAdd(day,-1,t1.[A-C/S BY]))
     when 7 then DateAdd( day, -2, t1.[A-C/S BY] )
     when 1 then DateAdd( day, -3, t1.[A-C/S BY] )
    else   t1.[A-C/S BY]-1--t1.[A-C/S BY]-1
END
FROM WORKORDERS T1
     INNER JOIN inserted i ON T1.[WORK ORDER #] = i.[WORK ORDER #]
    END

我想知道它是否因为订购有没有?当我将所有上述触发器合并到一个SHIP BY字段时,所有其余空白设置更新为NUll

3 个答案:

答案 0 :(得分:0)

Quote from the manual

  

可以使用sp_settriggerorder指定要在表上执行的第一个和最后一个AFTER触发器。对于每个INSERT,UPDATE和DELETE操作,只能在表上指定一个第一个和最后一个AFTER触发器。 如果同一桌上有其他AFTER触发器,则会随机执行。

(强调我的)

答案 1 :(得分:0)

您无法设置所有触发器触发的方式,您还可以设置第一个触发器和最后一个触发器的执行顺序。 因此,如果你有5个触发器,你可以说A将是第一个,E将是最后一个。但C,D和E将随机执行。

这篇文章可能会有所帮助

https://docs.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-settriggerorder-transact-sql

答案 2 :(得分:0)

哦,男人 - 在单个桌子上有很多触发器......糟糕的juju,我认为控制执行顺序不是你想采取的方法。在只需要多个触发器的地方,他们应该做的工作不依赖于其他触发器来完成他们的工作。它们应该更完全孤立。

在我们到达那里之前,你有一些表达方式在你的第一个触发器中没有任何意义......比如

WHEN t1.[RE-COMMIT DATE] =Null

...当ANSI_NULLS为ON(并且应该始终为ON)时,您永远不应该看到/使用它。

还有......像:

IsNull( t1.[Promised Date], Null )

......也没有任何意义。这样说,返回第一个值......但是如果那个是空的......那么返回第二个值。如果你从触发器中获取这些东西,它将更容易理解。

那么...如何在一个触发器中获取所有内容?我首先制作一个触发器......对承诺日期的变化很敏感。毕竟,一切都可以看作是基于此安排的。也就是说,使你的触发器尽可能明显......并根据需要将嘈杂的部分委托给函数,过程和视图。

所以,我会放弃所有那些讨厌的东西,从简单的东西开始,比如......

create trigger [SetWorkflowDates] on dbo.WORKORDERS for insert, update as
begin

  set nocount on, datefirst 7

  update dbo.WORKORDERS
    set 
      [Ship By]     = dbo.CalcDate('ship',  [Calc Promised Date],[Promised Date],[Re-Commit Date]),
      [Mount By]    = dbo.CalcDate('mount', [Calc Promised Date],[Promised Date],[Re-Commit Date]),
      [A-Powder By] = dbo.CalcDate('powder',[Calc Promised Date],[Promised Date],[Re-Commit Date]),
      [A-Fab By]    = dbo.CalcDate('fab',   [Calc Promised Date],[Promised Date],[Re-Commit Date]),
      [A-Print By]  = dbo.CalcDate('print', [Calc Promised Date],[Promised Date],[Re-Commit Date]),
      [A-C/S By]    = dbo.CalcDate('cs',    [Calc Promised Date],[Promised Date],[Re-Commit Date]),
      [A-Cut By]    = dbo.CalcDate('cut',   [Calc Promised Date],[Promised Date],[Re-Commit Date])
  from
    dbo.WORKORDERS wo
    inner join
    inserted i
    on
      wo.[Work Order #] = i.[Work Order #]
    left outer join
    deleted d
    on
      i.[Work Order #] = d.[Work Order #]
  where
    isnull(i.[Calc Promised Date],getdate()) != 
    isnull(d.[Calc Promised Date],getdate()) 
      or
    isnull(i.[Promised Date],getdate()) != 
    isnull(d.[Promised Date],getdate()) 
      or
    isnull(i.[Re-Commit Date],getdate()) != 
    isnull(d.[Re-Commit Date],getdate())
end

请注意,这应该使条件适用于插入或更新。

很好,小而清晰,很多比一大堆触发器更容易调试。

所以...触发器将不会编译,直到你在那里定义CalcDate函数...一个函数,它采用管理日期...并根据阶段计算另一个日期。你可以很好地将它从触发器中解脱出来......这样你就可以在不拉扯头发的情况下阅读和理解触发器。

也许CalcDate可能是这样的:

create function dbo.CalcDate
( 
  @stage varchar(8), @calc date, @prom date, @recommit date 
) 
returns date as
begin

  declare @result date =
    case datepart( weekday, @calc )
      when 7 then 
        dateadd( day, -1, @calc )
      when 1 then 
        dateadd( day, -2, @calc )
      else
        coalesce( @recommit, @prom )
     end

   if ( @stage = 'ship' ) return ( @result );

   set @result = dbo.PreviousWorkDay( @result );       
   if ( @stage = 'mount' ) return ( @result );  

   set @result = dbo.PreviousWorkDay( @result );       
   if ( @stage = 'powder' ) return ( @result ); 

   set @result = dbo.PreviousWorkDay( @result );
   if ( @stage = 'fab' ) return ( @result );       

   set @result = dbo.PreviousWorkDay( @result );
   if ( @stage = 'print' ) return ( @result );

   set @result = dbo.PreviousWorkDay( @result );
   if ( @stage = 'cs' ) return ( @result );

   set @result = dbo.PreviousWorkDay( @result );
   if ( @stage = 'cut' ) return ( @result );

   raiserror( 'Unrecognized stage', 16, 1 );

end

所以...现在我可以看到CalcDate根据阶段计算工作阶段......并且在工作流规则发生变化时很容易更新。

...然后最后,PreviousWorkDay函数减去一天...看它是否是工作日,如果不是,则减去另一个直到它是工作日:

create function dbo.PreviousWorkDay( @date date ) returns date as
begin
  set @date = dateadd( day, -1, @date )
  return
  (
    select case datepart( weekday, @date )
      when 7 then dateadd( day, -1, @date )
      when 1 then dateadd( day, -2, @date )
      else @date
    end
  )
end

所有代码都可以理解 - 函数名称说出他们做了什么......他们不会尝试做太多(或者不够)。修复和更新更容易。计划并简化每个机会。

注意:您应该删除之前的问题。当你提问两次因为你第一次不喜欢这些答案时,它只会让SO人感到不安。当你这样做时,你不会总是得到善意的待遇。

相关问题