一对一的父子关系sql server

时间:2012-10-26 10:13:48

标签: sql-server parent-child

我的表格包含字段TransactionIDAmountParentTransactionID 可以取消交易,以便将amountParentTransactionID作为已取消TransactionID的新条目发布。

让我们说一个交易

  

1 100 NULL

我取消了以上条目,它会像

  

2 -100 1

再次取消了上述交易,所以应该

  

3 100 2

当我拿到时,我应该得到记录3作为ID 1和2被取消。 结果应该是

  

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

答案 0 :(得分: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是可能取消的交易。如果没有取消交易(即TransactionId t2不存在),请返回该行。

我不确定你的最后一句话,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),它将显示。