我有一个事务表,它跟踪事务的所有细节,每个事务都可以有一个相关的事务。我在查询时遇到问题,无法找到相关交易池中的所有交易。
实施例: 2表:交易和相关交易
RelatedTransactions有一个TransactionID和一个RelatedTransactionID
说我有5笔交易 1与2有关 2与3有关 3与4有关 4与5相关
TransactionID RelatedTransactionID 1 2 2 3 3 4 4 5
我想要一个来自RelatedTransaction表的查询,如果提供了ID 1(或2或3或4或5),它将返回1,2,3,4,5
起初看起来很简单......我有一个查询
SELECT RelatedTransactionID FROM RelatedTransactions WHERE TransactionID = 1
当所有相关交易都有1作为父交易时,它显然有效。
所以,接下来我添加的内容与获取TransID 1是相关交易的所有内容相反
我添加了
SELECT TransactionID WHERE RelatedTransactionID = 1
直到人际关系变得更加有效。
我从那里开始添加了一个临时表来帮助我。
create table #RTS (TransactionID int );
INSERT INTO #RTS SELECT tr.TransactionID FROM TransactionsRelated tr WHERE tr.RelatedTransactionID = @ID;
INSERT INTO #RTS SELECT tr.RelatedTransactionID FROM TransactionsRelated tr WHERE tr.TransactionID = @ID;
INSERT INTO #RTS SELECT @ID;
INSERT INTO #RTS SELECT tr.TransactionID FROM TransactionsRelated tr WHERE tr.TransactionID IN (SELECT TransactionID FROM TransactionsRelated WHERE RelatedTransactionID = @ID);
INSERT INTO #RTS SELECT tr.TransactionID FROM TransactionsRelated tr WHERE tr.RelatedTransactionID IN (SELECT TransactionID FROM TransactionsRelated WHERE RelatedTransactionID = @ID);
INSERT INTO #RTS SELECT tr.TransactionID FROM TransactionsRelated tr WHERE tr.TransactionID IN (SELECT RelatedTransactionID FROM TransactionsRelated WHERE TransactionID = @ID);
INSERT INTO #RTS SELECT tr.TransactionID FROM TransactionsRelated tr WHERE tr.RelatedTransactionID IN (SELECT RelatedTransactionID FROM TransactionsRelated WHERE TransactionID = @ID);
如果我仍然比那更深,我仍然没有得到一切。
所以我接受了那个temptable并添加了查询以获取当前事务的所有相关事务。
INSERT INTO #RTS SELECT tr.TransactionID FROM #RTS rts INNER JOIN TransactionsRelated tr on tr.RelatedTransactionID = rts.TransactionID;
INSERT INTO #RTS SELECT tr.RelatedTransactionID FROM #RTS rts INNER JOIN TransactionsRelated tr on tr.TransactionID = rts.TransactionID;
当我意识到我仍然没有全部覆盖时,我只是再做了3次以确保我会处理它们。我的最终查询是
create table #RTS (TransactionID int );
INSERT INTO #RTS SELECT tr.TransactionID FROM TransactionsRelated tr WHERE tr.RelatedTransactionID = @ID;
INSERT INTO #RTS SELECT tr.RelatedTransactionID FROM TransactionsRelated tr WHERE tr.TransactionID = @ID;
INSERT INTO #RTS SELECT @ID;
INSERT INTO #RTS SELECT tr.TransactionID FROM TransactionsRelated tr WHERE tr.TransactionID IN (SELECT TransactionID FROM TransactionsRelated WHERE RelatedTransactionID = @ID);
INSERT INTO #RTS SELECT tr.TransactionID FROM TransactionsRelated tr WHERE tr.RelatedTransactionID IN (SELECT TransactionID FROM TransactionsRelated WHERE RelatedTransactionID = @ID);
INSERT INTO #RTS SELECT tr.TransactionID FROM TransactionsRelated tr WHERE tr.TransactionID IN (SELECT RelatedTransactionID FROM TransactionsRelated WHERE TransactionID = @ID);
INSERT INTO #RTS SELECT tr.TransactionID FROM TransactionsRelated tr WHERE tr.RelatedTransactionID IN (SELECT RelatedTransactionID FROM TransactionsRelated WHERE TransactionID = @ID);
INSERT INTO #RTS SELECT tr.TransactionID FROM #RTS rts INNER JOIN TransactionsRelated tr on tr.RelatedTransactionID = rts.TransactionID;
INSERT INTO #RTS SELECT tr.RelatedTransactionID FROM #RTS rts INNER JOIN TransactionsRelated tr on tr.TransactionID = rts.TransactionID;
INSERT INTO #RTS SELECT tr.TransactionID FROM #RTS rts INNER JOIN TransactionsRelated tr on tr.RelatedTransactionID = rts.TransactionID;
INSERT INTO #RTS SELECT tr.RelatedTransactionID FROM #RTS rts INNER JOIN TransactionsRelated tr on tr.TransactionID = rts.TransactionID;
INSERT INTO #RTS SELECT tr.TransactionID FROM #RTS rts INNER JOIN TransactionsRelated tr on tr.RelatedTransactionID = rts.TransactionID;
INSERT INTO #RTS SELECT tr.RelatedTransactionID FROM #RTS rts INNER JOIN TransactionsRelated tr on tr.TransactionID = rts.TransactionID;
INSERT INTO #RTS SELECT tr.TransactionID FROM #RTS rts INNER JOIN TransactionsRelated tr on tr.RelatedTransactionID = rts.TransactionID;
INSERT INTO #RTS SELECT tr.RelatedTransactionID FROM #RTS rts INNER JOIN TransactionsRelated tr on tr.TransactionID = rts.TransactionID;
SELECT DISTINCT t.ID, t.CreateDate, t.TransactionDate, t.Amount, t.TypeID, t.SourceID, t.UserID, ts.Name as Source, tt.Name as TypeName, t.Subject
FROM Transactions t INNER JOIN #RTS r on r.TransactionID = t.ID INNER JOIN TransactionSources ts on t.SourceID = ts.ID INNER JOIN TransactionTypes tt on tt.ID = t.TypeID ORDER BY TransactionDate DESC
DROP TABLE #RTS;
这样可以正常工作,但我认为如果一个事务有20多个级别的关系,它可能无法达到它们。
现在该产品正常运行,我真正想知道的是,如果有更好的递归方式在SQL中执行此操作(如果重要的话,MSSQL / Azure)。必须有更好的方法。
答案 0 :(得分:0)
我认为你需要的是一个递归查询。
在SQL Server 2005及更高版本中,您可以使用Common Table Expressions
编写它E.g。
WITH RecursiveTransactions AS
(
SELECT RelatedTransactionID, TransactionID FROM RelatedTransactions WHERE RelatedTransactionID IS NULL
UNION ALL
SELECT RelatedTransactionID, TransactionID FROM RelatedTransactions a JOIN RecursiveTransactions cte ON cte.TransactionID = a.RelatedTransactionID
)
SELECT RelatedTransactionID, TransactionID FROM RecursiveTransactions
WHERE TransactionID = @ID
如果您的DBMS不支持CTE,那么您可以编写一个递归SP,它基本上将@id作为输入并使用relatedID调用自身为@id
Example:
CREATE PROCEDURE RECURSIVETRANSACTIONID AS
(@ID int)
BEGIN
IF #temp does not exists then
CREATE #temp
END IF
INSERT INTO #temp
SELECT RelatedTransactionID, TransactionID FROM RecursiveTransactions
WHERE TransactionID = @ID
IF(@id is not null) then -- this check makes sure it terminates when relation is not found (i.e. for last element)
EXEC RECURSIVETRANSACTIONID(SELECT RelatedTransactionID FROM #temp)
END