订单依据的T-SQL更新

时间:2013-07-18 19:46:11

标签: sql-server tsql

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

  1. 使用日期范围内的审核记录创建@results临时表。
  2. 使用实体的当前值创建@currentValues临时表。
  3. 更新@results表以存储新值
  4. 以下是审计表的结构:

    • AuditId uniqueidentifier NEWID()
    • AuditDate datetime GETDATE()
    • UserId uniqueidentifier
    • EntityId uniqueidentifier
    • ColumnName nvarchar(100)
    • OldValue 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
    

    现在,如果我错了,请纠正我,当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
    

1 个答案:

答案 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