我正在尝试编写一个存储过程,它会在日期范围之间提供审计信息。 Audit表存储审核日期,列名称和旧值。我想在结果集中显示旧值和新值。我需要从下一个最近的审计条目或实体本身获取新值。存储过程是一个多步骤的方法来获取我需要的结果集。
以下是审计表的结构:
这是sql:
CREATE PROC GetAuditSummary
@StartDate datetime = NULL,
@EndDate datetime = NULL
AS
DECLARE @Results table(
AuditId uniqueidentifier,
AuditDate datetime,
UserId uniqueidentifier,
EndityId uniqueidentifier,
ColumnName nvarchar(100),
OldValue nvarchar(MAX),
NewValue nvarchar(MAX)
INSERT INTO @Results(AuditId, AuditDate, UserId, EntityId, ColumnName, OldValue)
SELECT AuditId, AuditDate, UserId, EntityId, ColumnName, OldValue
FROM Audit
WHERE (AuditDate >= @StartDate) AND (AuditDate < @EndDate)
DECLARE @CurrentValues table(
EntityId uniqueidentifier,
ColumnName nvarchar(100),
Value nvarchar(MAX)
)
--Lengthy Code to fill @CurrentValues temp table. Assume @CurrentValues is populated
UPDATE @Results
SET NewValue = n.Value
FROM @Results r INNER JOIN
(SELECT AUditId, AuditDate, EntityId, ColumnName, OldValue AS Value
FROM Audit
UNION ALL
SELECT NULL, GETDATE(), EntityId, ColumnName, Value
FROM @CurrentValues
ORDER BY AuditDate DESC
) n ON n.EntityId = r.EntityId AND
n.ColumnNmae = r.ColumName NAD
n.AuditDate > r.AuditDate
SELECT * FROM @Results ORDER BY AuditDate DESC
现在,如果我错了,请纠正我,当update语句执行时,NewValue应设置为连接结果集中的最后一个匹配行,因为我有AuditDate排序的子查询,最接近于来自@Results的当前记录应该是设置为NewValue的值。我试过这个,但是我收到一个错误,告诉我我不能在子查询中使用Order By。还有另一种方法吗?我对任何建议持开放态度,但我需要考虑性能,因为结果中可能有数千行。
- 编辑
这是让它运转的一种方法,但我不确定它是最好的性能。
UPDATE @Results
SET NewValue = COALESCE(
(SELECT TOP 1 a.OldValue
FROM Audit a
WHERE (a.EntityId = r.EntityId) AND
(a.ColumnName = r.ColumnName) AND
(a.AuditDate > r.AuditDate)
ORDER BY a.AuditDate),
(SELECT TOP 1 c.Value
FROM @CurrentValues c
WHERE (c.EntityId = r.EntityId) AND
(c.ColumnName = r.ColumnName))
FROM @Results r
答案 0 :(得分:1)
我会使用Row_Number或Rank函数来获取最后一个匹配行之后的行。
以下示例应该有效,如果您希望在匹配日期后想要最近的记录,则可能需要更改(按n.AuditDate排序)(按n.AuditDate desc排序)。
UPDATE @Results
SET NewValue = n.Value
FROM @Results r
INNER JOIN
(
select n.EntityId, n.ColumnName, n.Value, Row_Number() over(partition by n.EntityId, n.ColumnName order by n.AuditDate) RowNumber
from
@Results ir
inner join (
SELECT AuditDate, EntityId, ColumnName, OldValue AS Value
FROM Audit
UNION ALL
SELECT GETDATE(), EntityId, ColumnName, Value
FROM @CurrentValues
) inn on inn.EntityId = ir.EntityId AND
inn.ColumnNmae = ir.ColumName NAD
inn.AuditDate > ir.AuditDate
) n ON n.EntityId = r.EntityId AND
n.ColumnNmae = r.ColumName AND
n.RowNumber = 1