2017-04-10 70 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觸發器,它們會隨機執行。

(重點煤礦)