更好地替代INSTEAD OF INSERT,UPDATE触发器

时间:2011-08-12 23:51:47

标签: sql-server triggers

我在一家安全承包公司工作,我的数据库中有一个表,用于存储已调整工作PO的小时/次数。对于每个工作日期,财务部门将输入供应商的可计费开始和结束时间,以及客户端的可计费开始和结束时间。大多数情况下,供应商和客户的计费时间是相等的,除非在极少数情况下。

我们的系统工作方式,供应商的开始和结束时间始终更新客户端的开始和结束时间,除非客户端的开始和结束时间与供应商的开始和结束时间不同。为了存储这些信息,我有一个包含这些列的表:

  • 作业ID
  • PostNumber
  • StartTime(供应商开始时间)
  • ClosingTime(供应商开始时间)
  • ClientStartTime
  • ClientClosingTime

由于供应商和客户端的开始和结束时间通常需要保持彼此同步,我认为我会使用触发器来处理它。因为我需要访问当前值以将它们与新值进行比较,所以看起来INSTEAD OF INSERT,UPDATE触发器是可行的方式,除了我首先对触发器并不疯狂,并且依赖于触发器执行我的所有插入和更新到这个表让我感到紧张。也许这是一种非理性的恐惧,但我通常会尽量远离触发器。然而,在这种情况下,它似乎是最好的选择。

这是我的触发器,它应该使逻辑清晰:

ALTER TRIGGER [dbo].[<UpdateAdjustedHours>]
   ON  [dbo].[<AdjustedHoursTable>] 
   INSTEAD OF INSERT, UPDATE
AS 
BEGIN

    IF (NOT EXISTS(SELECT CurrentValues.JobID FROM WorkOrderDetailAdjustment CurrentValues, Inserted NewValues WHERE CurrentValues.JobID = NewValues.JobID AND CurrentValues.PostNumber = NewValues.PostNumber))
    BEGIN

        INSERT INTO WorkOrderDetailAdjustment
            SELECT  Inserted.JobID,
                    Inserted.PostNumber,
                    Inserted.StartTime,
                    Inserted.ClosingTime,
                    ISNULL(Inserted.ClientStartTime, Inserted.StartTime),
                    ISNULL(Inserted.ClientClosingTime, Inserted.ClosingTime)    
            FROM    Inserted                

    END
    ELSE BEGIN

        UPDATE  CurrentValues
        SET     CurrentValues.StartTime = ISNULL(NewValues.StartTime, CurrentValues.StartTime),
                CurrentValues.ClosingTime = ISNULL(NewValues.ClosingTime, CurrentValues.ClosingTime),
                CurrentValues.ClientStartTime = (
                    CASE WHEN DATEDIFF(SECOND, CurrentValues.ClientStartTime, CurrentValues.StartTime) != 0 THEN 
                        ISNULL(NewValues.ClientStartTime, CurrentValues.ClientStartTime) 
                    ELSE 
                        NewValues.StartTime 
                    END
                ),
                CurrentValues.ClientClosingTime = (
                    CASE WHEN DATEDIFF(SECOND, CurrentValues.ClientClosingTime, CurrentValues.ClosingTime) != 0 THEN
                        ISNULL(NewValues.ClientClosingTime, CurrentValues.ClientClosingTime)
                    ELSE
                        NewValues.ClosingTime
                    END
                )
        FROM    WorkOrderDetailAdjustment CurrentValues, Inserted NewValues
        WHERE   CurrentValues.JobID = NewValues.JobID AND CurrentValues.PostNumber = NewValues.PostNumber

    END

END

我想知道的是,如果有更好的方法可以做到这一点。我对所有建议持开放态度,但如果可能的话,我希望将其保留在数据库级别。我也很乐意听到我选择了最好的方法,但出于某种原因我对此表示怀疑。

感谢您的帮助!

2 个答案:

答案 0 :(得分:2)

你可以做的一件事......如果你的操作有意义,就是在你的表中添加一个持久的计算列。 (我在你的描述中推断你确实希望存储这个值。如果没有,你不需要持久化选项。)

它可能像coalesce(client_start_time,vender_start_time)。

或者,您可以创建执行相同操作的视图。我并不为观点而疯狂,因为它们容易被滥用,但它们并不总是坏事。

Eithe rway,当它实际上与vender_start_time不同时,你只需输入client_start时间。你可以避免使用触发器。

答案 1 :(得分:1)

我建议在应用程序的业务逻辑层处理它,而不是在数据库中处理它。

我们经历了一个痛苦的时期,将业务规则放在“无处不在” - 在应用程序后端,在存储过程和触发器的数据库中。我们重新设计了我们的方法,并在严格的层次中拆分应用程序。现在开发和维护更加顺畅。在我看来,您描述的任务 - 保持可计费数据同步 - 是业务逻辑的一部分,应该在那里实现。