如果所有事务都被一个新事务设置 ParentTransactionId 取消,它可以使用简单的LEFT JOIN 来完成;
SELECT t1.* FROM Transactions t1
LEFT JOIN Transactions t2
ON t1.TransactionId = t2.ParentTransactionId
WHERE t2.TransactionId IS NULL;
t1 是我们当前正在查看的事务,t2 是可能取消的事务。如果没有取消事务(即t2 的TransactionId 不存在),则返回该行。
不过,我不确定你最后的声明,If I cancelled the 3rd entry no records should return.。如果不向表中添加新事务,您将如何取消 #3?您可能还有其他一些您没有告诉我们的取消条件...?
Simple SQLfiddle demo.
编辑:由于您不想要取消的交易(或者更确切地说是取消次数为奇数的交易),您需要一个相当复杂的递归查询来确定是否显示最后一笔交易;
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 再次启动,here is a fiddle to test with。
查询的简短解释可能是有序的,即使以简单的方式有点难以做到;它定义了一个递归“视图”ChangeLog,它跟踪取消和原始事务 id 从原始事务到系列中的最后一个事务(一个系列是具有相同 OriginalTransactionId 的所有事务)。之后,它将ChangeLog 与自身连接以查找最后一个条目(即所有没有取消交易的交易)。如果在系列中找到的最后一个条目不是取消 (IsCancel=0),它将显示出来。