触发器:根据另一列的值更新列

Trigger : update column based on value of another column

我们有一个 table,其中包含一个状态列,并且与该列关联的是一个用于跟踪状态值更改时间的列。

例如,我们有状态 'Off' 和状态 'Found Off' 以及关联的列 DateOffDateFoundOff。我正在尝试创建一个触发器来在状态更改时更新这些日期列。

这对我来说似乎很简单,但是当 Status 更改关联的日期列时正确更新,但另一个日期列变为空。因此,如果我更改 Status = 'Off' DateOff 具有正确的日期,但 DateFoundOff 变为空,反之亦然。

我创建了两个触发器 - 第一个是:

ALTER TRIGGER [GIS].[UPDATE_FOUNDOFF]
ON [GIS].[METEROUTAGEPOINTS]
AFTER UPDATE
AS 
    IF (UPDATE (OutageStatus))
    BEGIN
        SET NOCOUNT ON;

        UPDATE [gis].[METEROUTAGEPOINTS] 
        SET DateFoundOff = CURRENT_TIMESTAMP
        FROM gis.METEROUTAGEPOINTS mop 
        INNER JOIN inserted AS i ON i.ConObject = mop.ConObject
        WHERE i.OutageStatus = 'Found Off'
    END

第二个

ALTER TRIGGER [GIS].[UPDATE_DATES]
ON  [GIS].[METEROUTAGEPOINTS]
AFTER UPDATE
AS 
    IF (UPDATE (OutageStatus))
    BEGIN
        SET NOCOUNT ON;

        UPDATE [gis].[METEROUTAGEPOINTS] 
        SET DateOff = CURRENT_TIMESTAMP 
        FROM gis.METEROUTAGEPOINTS mop 
        INNER JOIN inserted AS i ON i.ConObject = mop.ConObject
        WHERE i.OutageStatus = 'Off'
    END

我根本不明白一个触发器如何将日期列的值更改为与当前状态值无关的空值。

谢谢。

编辑:发现问题不在于触发器,而在于用于编辑数据的工具如何保持某些东西。不确定我明白为什么,但通过更改编辑工作流程,问题得到了解决。将答案标记为正确基于它提供了一种更好的编写触发器的方法

您的更新语句都没有将 DateFoundOffDateOff 更改为 null。一定是有其他事情发生了。

但是我会按如下方式改进您的触发器:

  1. 只使用一个触发器,每个触发器都有开销,一个触发器和一个更新语句 运行 比 2 个更快。
  2. 您实际上并没有检查状态是否已更改,您只是在检查更新是否包含该列。添加针对 deleted 的检查 table 实际上检查值是否已更改。
ALTER TRIGGER [GIS].[UPDATE_FOUNDOFF]
ON [GIS].[METEROUTAGEPOINTS]
AFTER UPDATE
AS 
BEGIN
    -- Avoid doing any processing if no rows are updated
    IF NOT EXISTS (SELECT 1 FROM Inserted) RETURN;

    SET NOCOUNT ON;

    IF UPDATE(OutageStatus) BEGIN
        UPDATE [gis].[METEROUTAGEPOINTS] SET
            DateFoundOff = CASE WHEN i.OutageStatus = 'Found Off' AND d.OutageStatus <> 'Found Off' THEN CURRENT_TIMESTAMP ELSE DateFoundOff END
            , DateOff = CASE WHEN i.OutageStatus = 'Off' AND d.OutageStatus <> 'Off' THEN CURRENT_TIMESTAMP ELSE DateOff END
        FROM gis.METEROUTAGEPOINTS mop 
        INNER JOIN inserted AS i ON i.ConObject = mop.ConObject
        INNER JOIN deleted AS d ON d.ConObject = mop.ConObject;
    END;
END;