【问题标题】:Better alternative to INSTEAD OF INSERT, UPDATE triggerINSTEAD OF INSERT、UPDATE 触发器的更好替代方案
【发布时间】:2011-08-12 23:51:46
【问题描述】:

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

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

  • 工作 ID
  • 邮政编号
  • StartTime(供应商开始时间)
  • ClosingTime(供应商开始时间)
  • 客户端开始时间
  • 客户端关闭时间

由于供应商和客户端的开始和结束时间通常需要彼此保持同步,我想我会使用触发器来处理它。因为我需要访问当前值以将它们与新值进行比较,所以似乎 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

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

感谢您的帮助!

【问题讨论】:

    标签: sql-server triggers


    【解决方案1】:

    您可以做的一件事...如果它对您的操作有意义,就是向您的表中添加一个持久计算列。 (我从您的描述中推断您实际上希望存储此值。如果不是,则不需要持久选项)。

    它可能类似于 coalesce(client_start_time, vender_start_time)。

    或者,您可以创建执行相同操作的视图。我并不热衷于视图,因为它们很容易被滥用,但它们并不总是坏的。

    不管怎样,您只需要输入实际上不同于 vender_start_time 的 client_start 时间。你可以避免使用触发器。

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多