2017-04-10 83 views
0

我使用多触发器在Sqlserver中使用触发器实现backward date schedulingsql服务器触发器是否具有执行顺序?

但是,这里有线正在发生。以下是我注意到

  • AFTER INSERT以下三个字段更新SHIP BY,A-MOUNT BY,A-POWDER BY
  • 当我改变的东西,以相同的记录和保存A-FAB更新
  • 而对于第二次当我改变的东西,以相同的记录和保存A-C\S, A-PRINT BY更新

我要更新3次得到各方面更新

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

舰=客户的承诺的日期-1

A-MOUNT BY =舰-1

A-粉体= A-MOUNT BY - 1或粉BY也等于船由日期-2

A-FAB BY = A-粉体 - 1 OR A-FAB BY也等于船由日期-3

AC/S BY = A-FAB BY或AC/S BY也等于按日期发货-4

A-CUT BY = AC/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-粉体

/****** 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-削减

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

+0

当您在同一个表上有多个相同类型的触发器(INSERT,UPDATE,DELETE)时,您无法保证执行顺序。可以将其中的一个指定为第一个始终,或者将其中的一个指定为总是最后一个,但对于不止于此,您不能指定完整的订单。因此,你的触发器不应该依赖于它们的运行顺序。坦率地说,不应该使用相同的数据。 – pmbAustin

+0

当我演示如何将所有这些触发器组合到一个更新语句中时,我们讨论了这一点。 http://stackoverflow.com/questions/43265377/disadvantage-of-having-multiple-triggers-on-the-same-table –

+0

@SeanLange当我合并所有触发器到一个,因为你建议只是船舶BY字段更新所有其余设置为空白或NULL – Joe

回答

0

哦男人 - 有很多触发对这样的...坏朱朱一个表,我想控制的执行顺序是不是你想要的方法采取。在那里只需要多触发器,他们应该做的工作,不依赖于其他触发器先做他们的工作。他们应该更加完全孤立。

我们到那里之前,你必须表现的是没有任何意义在你第一次触发...之类的东西

WHEN t1.[RE-COMMIT DATE] =Null 

...你应该不会看到/使用时ANSI_NULLS为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可能是这样的:

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 

所有代码那么有道理 - 函数名称说明他们做了什么......他们不会尝试做太多(或不够)。修复和更新要容易得多。计划和简化每一个机会。

注意:你应该删除以前的问题。当你提出问题两次时,它会让你反感,因为你第一次不喜欢答案。当你这样做时,你不会总是得到善良的待遇。

+0

谢谢@clay我得到了'Msg 156,Level 15,State 1,Procedure SetWorkflowDates,Line 22 关键字'left''附近的语法错误'这行中的错误'wo。[Work Order#] = i。[Work Order#], left outer join' – Joe

+0

我的坏...有一个逗号 - 我会修复它 - 但你必须首先定义函数......几乎与我描述的相反顺序。那里 - 我修复了它的一部分。没有保证,虽然... – Clay

+0

是的,我在做什么,谢谢 – Joe

0

Quote from the manual

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

(重点煤矿)