递归CTE以及如何克服循环参考误差

问题描述 投票:0回答:1

我有一个脚本旨在找到原始位置。 它从这样的表格开始:

身份证 上一个ID 地点
2 1235
3 2 1236
4 3 1239
8 11 1237
9 8 1234
10 9 1235
11 10 1237

我想找到选定数量的 ID 值的原始位置

身份证号码
2
4
8
10
11

我正在寻找的结果是:

lvl 身份证 原ID 地点 原地点
0 2 2 1235 1235
2 4 2 1239 1235
0 8 8 1237 1237
2 10 8 1235 1237
3 11 8 1237 1235

ID = 2 和 = 4 的输出良好。 然而,对于 8,10,11,这会导致循环引用并且代码中断。

问题:有没有办法解决这个问题,这样错误就不会发生:

声明终止。在语句完成之前最大递归100已经用完

并产生所需的输出?我知道 8 是根,因为它是该链中最小的数字,即使该链中存在循环引用

这是我迄今为止为 ID 2 和 4 生成输出的脚本。如果删除值 8,10,11,它就可以工作

DECLARE @IDs TABLE (
  ID INTEGER
  ,PreviousID INTEGER
  ,Location INTEGER
)

INSERT INTO @IDs
SELECT           2,null,1235
UNION ALL SELECT 3,2,1236
UNION ALL SELECT 4,3,1239
UNION ALL SELECT 8,11,1237
UNION ALL SELECT 9,8,1234
UNION ALL SELECT 10,9,1235
UNION ALL SELECT 11,10,1237

Select * from @IDs


DECLARE @ORDERID Table (OrderID nvarchar (100))
Insert into @ORDERID values
('2')
,('4')
--,('8')
--,('10')
--,('11')

;WITH q AS (
    SELECT 0 lvl,  ID, PreviousID,PreviousID LastId
        ,Location,Location as OriginalLocation
    FROM    @IDs
    where ID in (select OrderID from @ORDERID) 
    UNION ALL 
    SELECT lvl+1, q.ID,u.PreviousId,q.PreviousId LastId
       ,q.Location,u.Location
    FROM    q
            INNER JOIN @IDs u ON u.ID = q.PreviousID
            --and q.ID <> u.PreviousID and q.PreviousID <> u.ID
)
select lvl, ID, coalesce(LastId,Id) OriginalId,Location,OriginalLocation 
from q
where PreviousId is null
order by id;

非常感谢您的任何提示或建议。

进行编辑以解释为什么 8 是根。

sql-server t-sql
1个回答
0
投票
WITH q AS (
    SELECT 0 lvl
        , ID
        , PreviousID
        , PreviousID LastId
        , Location
        , Location AS OriginalLocation
        , CONVERT(bit, CASE WHEN PreviousID IS NULL OR PreviousId > Id THEN 1 ELSE 0 END) IsRoot
    FROM @IDs
    WHERE ID in (select OrderID from @ORDERID) 
  
    UNION ALL 
  
    SELECT lvl + 1
        , q.ID
        , u.PreviousId
        , q.PreviousId LastId
        , q.Location
        , u.Location
        , CONVERT(bit, CASE WHEN u.PreviousID IS NULL OR u.PreviousId > u.Id THEN 1 ELSE 0 END) IsRoot
    FROM q
    INNER JOIN @IDs u ON u.ID = q.PreviousID AND q.ID > u.Id
    where lvl < 20
)
SELECT lvl, ID, coalesce(LastId,Id) OriginalId, Location, OriginalLocation
FROM q
WHERE IsRoot = 1
ORDER BY id;
© www.soinside.com 2019 - 2024. All rights reserved.