我使用多个触发器在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
答案 0 :(得分:0)
可以使用sp_settriggerorder指定要在表上执行的第一个和最后一个AFTER触发器。对于每个INSERT,UPDATE和DELETE操作,只能在表上指定一个第一个和最后一个AFTER触发器。 如果同一桌上有其他AFTER触发器,则会随机执行。
(强调我的)
答案 1 :(得分:0)
您无法设置所有触发器触发的方式,您还可以设置第一个触发器和最后一个触发器的执行顺序。 因此,如果你有5个触发器,你可以说A将是第一个,E将是最后一个。但C,D和E将随机执行。
这篇文章可能会有所帮助
答案 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人感到不安。当你这样做时,你不会总是得到善意的待遇。