添加“上次发生时间”标志列

Shm*_*ski 2 sql-server greatest-n-per-group

我需要在包含 3 列的表中添加一列:

  1. GroupKey - 显示项目的编号。
  2. 状态 - 组根据插入日期所处的状态编号。状态编号可以前后更改多次。
  3. 插入日期 - 状态更改的时间和日期。

这 3 列永远不会改变。它就像一个“日志”表,只能添加行,不能删除或更改行

我需要的第四列(计算列)是一个标志列,它将显示状态是否是基于 insert_date 的最后一次状态更改。

如果是最后一个状态,则显示 1,否则显示 0。我希望我解释得足够好。下面是一个例子:

这是桌子。

Pau*_*ite 5

这不能用计算列来完成。一种选择是使用触发器:

样本数据

CREATE TABLE dbo.Example
(
    GroupKey integer NOT NULL,
    [Status] integer NOT NULL,
    inserted_date datetime NOT NULL DEFAULT GETUTCDATE(),
    IsLastTimeOccurred bit NOT NULL DEFAULT 'false',

    CONSTRAINT PK_dbo_Example_GroupKey_Status_inserted_date
    PRIMARY KEY CLUSTERED (GroupKey, [Status], inserted_date)
);

INSERT dbo.Example
    (GroupKey, [Status], inserted_date)
VALUES
    (11136, 10, '2015-03-30T13:01:50.153'),
    (11136, 11, '2015-03-30T13:02:03.590'),
    (11136, 12, '2015-03-30T13:02:08.980'),
    (11136, 10, '2015-04-30T09:37:40.477'),
    (11136, 11, '2015-04-30T09:37:46.400'),
    (11136, 12, '2015-04-30T09:38:04.177');
Run Code Online (Sandbox Code Playgroud)

初始设置

这假设所有行都以IsLastTimeOccurred= false 开头:

UPDATE E
SET IsLastTimeOccurred = 'true'
FROM dbo.Example AS E
WHERE NOT EXISTS
(
    SELECT * 
    FROM dbo.Example AS E2
    WHERE E2.GroupKey = E.GroupKey
    AND E2.[Status] = E.[Status]
    AND E2.inserted_date > E.inserted_date
);
Run Code Online (Sandbox Code Playgroud)

维护

以下触发器可确保在表更改时列保持正确:

CREATE TRIGGER trg_dbo_Example_AIUD
ON dbo.Example
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
    SET ROWCOUNT 0;
    SET NOCOUNT ON;

    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

    -- Holds group keys and the latest insert date
    CREATE TABLE #Changes
    (
        GroupKey integer NOT NULL,
        [Status] integer NOT NULL,
        inserted_date datetime NOT NULL,

        PRIMARY KEY (GroupKey, [Status])
    );

    -- Populate the temporary table    
    INSERT #Changes
    (
        GroupKey, 
        [Status],
        inserted_date
    )
    SELECT
        E.GroupKey, 
        E.[Status],
        MAX(E.inserted_date)
    FROM dbo.Example AS E
    WHERE EXISTS
    (
        SELECT * 
        FROM Inserted AS I
        WHERE I.GroupKey = E.GroupKey
        AND I.[Status] = E.[Status]

        UNION ALL

        SELECT * 
        FROM Deleted AS D
        WHERE D.GroupKey = E.GroupKey
        AND D.[Status] = E.[Status]        
    )
    GROUP BY
        E.GroupKey,
        E.[Status];

    -- Set the flag
    UPDATE E
    SET E.IsLastTimeOccurred =
        CASE WHEN E.inserted_date = C.inserted_date THEN 1 ELSE 0 END
    FROM #Changes AS C
    JOIN dbo.Example AS E
        ON E.GroupKey = C.GroupKey
        AND E.[Status] = C.[Status]
    WHERE
        E.inserted_date = C.inserted_date
        OR E.IsLastTimeOccurred = 'true';
END;
Run Code Online (Sandbox Code Playgroud)

这是处理插入、更新和删除的通用解决方案。它是在澄清问题之前写的,说明该表是仅插入的。即便如此,我可能会保留完整的一般逻辑;它不会花费太多,并且提供了一个安全网。