1

我正在尝试编写一个存储过程,它将为我提供日期范围之间的审计信息。审计表存储审计日期、列名和旧值。我想在结果集中显示旧值和新值。我需要从下一个最近的审计条目或从实体本身获取新值。存储过程是获取我需要的结果集的多步骤方法。

  1. 使用日期范围内的审计记录创建一个 @results 临时表。
  2. 使用来自实体的当前值创建一个 @currentValues 临时表。
  3. 更新@results 表以存储新值

这是审计表的结构:

  • AuditId 唯一标识符 NEWID()
  • AuditDate 日期时间 GETDATE()
  • 用户 ID 唯一标识符
  • EntityId 唯一标识符
  • 列名 nvarchar(100)
  • 旧值 nvarchar(MAX)

这是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

现在,如果我错了,请纠正我,当更新语句执行时,NewValue 应该设置为连接结果集中的最后一个匹配行,并且由于我有由 AuditDate 排序的子查询,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
4

1 回答 1

1

我会使用 Row_Number 或 Rank 函数来获取最后一个匹配行之后的行。

以下示例应该可以工作,如果您想要匹配日期之后的最新记录,您可能需要将 (order by n.AuditDate) 更改为 (order by 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
于 2013-07-18T20:01:07.730 回答