1

ある日付範囲の監査情報を提供するストアド プロシージャを作成しようとしています。監査テーブルには、監査日、列名、および古い値が格納されます。結果セットに古い値と新しい値を表示したいと考えています。次の最新の監査エントリまたはエンティティ自体から新しい値を取得する必要があります。ストアド プロシージャは、必要な結果セットを取得するための多段階アプローチです。

  1. 日付範囲内の監査レコードを含む @results 一時テーブルを作成します。
  2. エンティティからの現在の値で @currentValues 一時テーブルを作成します。
  3. @results テーブルを更新して新しい値を保存する

監査テーブルの構造は次のとおりです。

  • AuditId 一意の識別子 NEWID()
  • AuditDate 日時 GETDATE()
  • UserId 一意の識別子
  • EntityId 一意の識別子
  • 列名 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

ここで、私が間違っている場合は修正してください。更新ステートメントが実行されると、結合された結果セットの最後に一致する行に NewValue を設定する必要があります。 @Results は、NewValue に設定された値である必要があります。これを試してみましたが、サブクエリで Order By を使用できないというエラーが表示されます。これを行う別の方法はありますか?どんな提案も歓迎しますが、結果に何千行もある可能性があるため、パフォーマンスを考慮する必要があります。

- 編集

これを機能させる方法の 1 つを次に示しますが、これが最適なパフォーマンスかどうかはわかりません。

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 関数を使用して、最後に一致した行の後に行を取得します。

次の例が機能するはずです。一致した日付の後に最新のレコードが必要な場合は、(n.AuditDate による順序) を (n.AuditDate による順序) に変更することができます。

  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 に答える