Shm*_*ski 2 sql-server greatest-n-per-group
我需要在包含 3 列的表中添加一列:
这 3 列永远不会改变。它就像一个“日志”表,只能添加行,不能删除或更改行
我需要的第四列(计算列)是一个标志列,它将显示状态是否是基于 insert_date 的最后一次状态更改。
如果是最后一个状态,则显示 1,否则显示 0。我希望我解释得足够好。下面是一个例子:
这不能用计算列来完成。一种选择是使用触发器:
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)
这是处理插入、更新和删除的通用解决方案。它是在澄清问题之前写的,说明该表是仅插入的。即便如此,我可能会保留完整的一般逻辑;它不会花费太多,并且提供了一个安全网。