我有一个递归的CTE查询,但是在创建循环时失败了。我已经修复了简单循环(例如1 - > 2 - > 1),但无法修复更复杂的循环(例如1 - > 2 - > 3 - > 2)。
测试表有两列:Base和Parent。我想要一个包含所有祖先的清单。
如果从test2开始,我的查询将对下面的示例数据起作用,但在test1开始时则不行。
示例数据
Base Parent
---- ------
test1 test2
test2 test3
test3 test2
SQL查询(我的尝试修复标记在评论中)
;with sample_data (Base, Parent) as (
select 'test1', 'test2'
union select 'test2', 'test3'
union select 'test3', 'test2'
),
nt_list (Base, Ancestor, [level]) as (
select Base,
Parent Ancestor,
1 [level]
from sample_data
where Base = 'test1' -- START HERE
union all
select ntl.Base,
nt.Parent,
ntl.[level] + 1 [level]
from nt_list ntl
join sample_data nt on ntl.Ancestor = nt.Base
where nt.Parent <> ntl.Base -- fix recursive bug (e.g. 1 -> 2 -> 1)
-- WHAT I TRIED TO ADD BUT CANNOT: (e.g. 1 -> 2 -> 3 -> 2)
and nt.Parent in (select Ancestor from nt_list)
)
select distinct
ntl.Base,
ntl.Ancestor
from nt_list ntl
order by Ancestor
SQL错误:公用表表达式'nt_list'的递归成员具有多个递归引用。
答案 0 :(得分:2)
最终版本。假设'/'
永远不会成为基本名称或父名称的一部分。
;with sample_data (Base, Parent) as (
-- TEST 1
-- select 'test1', 'test2'
--union select 'test2', 'test3'
--union select 'test3', 'test2'
-- TEST 2
select 'test1', 'test2'
union select 'test2', 'test3'
union select 'test3', 'test4'
union select 'test3', 'test9'
union select 'test4', 'test5'
union select 'test5', 'test3'
union select 'test9', 'test8'
-- TEST 3
-- select 'test1', 'test2'
--union select 'test2', 'test3'
--union select 'test3', 'test1'
-- TEST 4
-- select 'test1', 'test1'
--union select 'test1', 'test2'
),
nt_list (Base, Ancestor, [level], [path]) as (
select Base,
Parent Ancestor,
1 [level],
'/' + convert(varchar(max), rtrim(Base)) + '/' [path]
from sample_data
where Base = 'test1' -- START HERE
union all
select ntl.Base,
nt.Parent,
ntl.[level] + 1 [level],
ntl.[path] + rtrim(nt.Base) + '/'
from nt_list ntl
join sample_data nt on ntl.Ancestor = nt.Base
where ntl.path not like '%/' + rtrim(nt.Parent) + '/%'
)
select distinct
ntl.Base,
ntl.Ancestor
from nt_list ntl
order by Ancestor
答案 1 :(得分:1)
您可以使用
;WITH nt_list (Base, Ancestor, [level], cycle, path)
AS (SELECT Base,
Parent Ancestor,
1 [level],
0 AS cycle,
CAST('.' AS VARCHAR(max)) + ISNULL(Parent, '') + '.' + Base + '.' AS [path]
FROM NoteTest
WHERE Base = 'test1'
UNION ALL
SELECT ntl.Base,
nt.Parent,
ntl.[level] + 1 [level],
CASE
WHEN ntl.[path] LIKE '%.' + LTRIM(nt.Base) + '.%' THEN 1
ELSE 0
END AS cycle,
ntl.[path] + LTRIM(nt.Base) + '.' AS [path]
FROM nt_list ntl
JOIN NoteTest nt
ON ntl.Ancestor = nt.Base
AND ntl.cycle = 0)
SELECT ntl.Base,
ntl.Ancestor
FROM nt_list ntl
ORDER BY Ancestor
答案 2 :(得分:0)
我目前的解决方法是添加级别限制(向查询添加and ntl.[level] <= 100
)并让select distinct
删除重复的条目。
答案 3 :(得分:0)
这种情况很完美,但正如您对更多项目所做的那样:
select 'test1', 'test2'
union select 'test2', 'test3'
union select 'test3', 'test4'
union select 'test4', 'test5'
union select 'test10', 'test11'
union select 'test11', 'test30'
...
结果应为:
test1 test1 <- adding this
test1 test2
test1 test3
test1 test4
test1 test5
test10 test10 <- adding this to multiple bases
test10 test11
test10 test30