1

フィールドを持つテーブルがあり、TransactionIDトランザクション をキャンセルできるため、新しいエントリがキャンセルされたものとして投稿されます。AmountParentTransactionIDamountParentTransactionIDTransactionID

トランザクションとしましょう

1 100 ヌル

上記のエントリをキャンセルしました。

2 -100 1

再び上記の取引をキャンセルしたので、そのようにする必要があります

3 100 2

フェッチすると、ID 1 と 2 がキャンセルされたため、レコード 3 を取得する必要があります。結果は

3 100 2

3 番目のエントリをキャンセルした場合、レコードは返されません。

SELECT * FROM Transaction t
WHERE NOT EXISTS (SELECT TOP 1 NULL FROM Transaction pt
WHERE (pt.ParentTransactionID = t.TransactionID OR t.ParentTransactionID = pt.TransactionID)
AND ABS(t.Amount) = ABS(pt.Amount))

これは、1 レベルのキャンセルのみが行われた場合に機能します。

4

1 に答える 1

1

すべてのトランザクションが取り消されるトランザクションに ParentTransactionId を設定する新しいトランザクションによって取り消される場合、単純なLEFT JOIN;を使用して行うことができます。

SELECT t1.* FROM Transactions t1
LEFT JOIN Transactions t2
  ON t1.TransactionId = t2.ParentTransactionId
WHERE t2.TransactionId IS NULL;

t1は、現在検討中のトランザクションでありt2、キャンセルされる可能性のあるトランザクションです。キャンセルするトランザクションがない (つまりTransactionIdfort2が存在しない) 場合は、行を返します。

私はあなたの最後の声明について確信が持てませんIf I cancelled the 3rd entry no records should return.. テーブルに新しいトランザクションを追加せずに #3 をキャンセルするにはどうすればよいでしょうか? あなたが私たちに伝えていないキャンセルの条件が他にあるかもしれません...?

シンプルな SQLfiddle デモ

編集: キャンセルされたトランザクション (またはキャンセル回数が奇数のトランザクション) が必要ないため、最後のトランザクションを表示するかどうかを判断するには、かなり複雑な再帰クエリが必要です。

WITH ChangeLog(TransactionID, Amount, ParentTransactionID, 
               IsCancel, OriginalTransactionID) AS
(
  SELECT TransactionID, Amount, ParentTransactionID, 0, TransactionID
  FROM Transactions WHERE ParentTransactionID IS NULL
  UNION ALL
  SELECT t.TransactionID, t.Amount, t.ParentTransactionID, 
         1-c.IsCancel, c.OriginalTransactionID
  FROM Transactions t
  JOIN ChangeLog c ON c.TransactionID = t.ParentTransactionID
) 
SELECT c1.TransactionID, c1.Amount, c1.ParentTransactionID
FROM ChangeLog c1
LEFT JOIN ChangeLog c2
  ON c1.TransactionID < c2.TransactionID
     AND c1.OriginalTransactionID = c2.OriginalTransactionID
WHERE c2.TransactionID IS NULL AND c1.IsCancel=0

これは、3 つのトランザクションの例では、最後の行を表示しますが、最後の行がキャンセルされた場合、何も返されません。

SQLfiddle が再び起動したので、テストするフィドルを次に示します。

簡単な方法で行うのが少し難しい場合でも、クエリの簡単な説明が必要な場合があります。これは、一連の元のトランザクションから最後のトランザクションまでのキャンセルと元のトランザクション ID を追跡する再帰的な「ビュー」を定義しますChangeLog(一連のトランザクションは、同じ OriginalTransactionId を持つすべてのトランザクションです)。その後、ChangeLog自身と結合して最後のエントリ (つまり、キャンセルするトランザクションを持たないすべてのトランザクション) を見つけます。シリーズで見つかった最後のエントリがキャンセル ( IsCancel=0) でない場合、それが表示されます。

于 2012-10-26T10:24:42.217 に答える