用守卫停止递归 CTE
Stopping recursive CTE with a guard
我有以下从源到目标的分层数据,我想在出现对现有源的引用时停止
create table #temp (source int, destination int);
insert into #temp values (1,3), (3,7), (7,9), (9,1);
WITH cte (Source, Destination, Level, Sources)
AS
(
SELECT Source, Destination, 0 AS Level, CAST(Source AS VARCHAR(MAX)) + ',' AS Sources
FROM #temp
WHERE [Source] = 1
UNION ALL
SELECT t.[Source], t.Destination, cte.[Level] + 1, cte.Sources + CAST(t.Source AS VARCHAR(MAX)) + ','
FROM #temp t
INNER JOIN cte ON cte.Destination = t.[Source] AND (CAST(t.Destination AS VARCHAR(MAX)) + ',' NOT LIKE '%' + cte.Sources + '%')
)
select * from cte
drop table #temp;
然而,当 运行 这个时,我仍然得到最大递归错误。我应该如何正确编写保护条款?我想要的是前 3 个结果。
在 CTE 的递归部分添加 where
子句。
create table #temp (source int, destination int);
insert into #temp values (1,3), (3,7), (7,9), (9,1);
WITH cte (Source, Destination, Level, Sources)
AS
(
SELECT Source, Destination, 0 AS Level, CAST(Source AS VARCHAR(MAX)) + ',' AS Sources
FROM #temp
WHERE [Source] = 1
UNION ALL
SELECT t.[Source], t.Destination, cte.[Level] + 1, cte.Sources + CAST(t.Source AS VARCHAR(MAX)) + ','
FROM #temp t
INNER JOIN cte ON cte.Destination = t.[Source] AND (CAST(t.Destination AS VARCHAR(MAX)) + ',' NOT LIKE '%' + cte.Sources + '%')
where cte.Level < 2 -- stop after 3 levels (0,1,2)
)
select * from cte
drop table #temp;
这里,在CTE的递归成员中:
INNER JOIN cte
ON cte.Destination = t.[Source]
AND (CAST(t.Destination AS VARCHAR(MAX)) + ',' NOT LIKE '%' + cte.Sources + '%')
您的 LIKE
操作数是错误的。相反:
INNER JOIN cte
ON cte.Destination = t.[Source]
AND cte.Sources NOT LIKE CONCAT('%', t.Destination, '%')
即:目的地应该属于已经访问过的来源列表。请注意,使用 CONCAT()
会强制将数字转换为字符串,从而缩短表达式。
我有以下从源到目标的分层数据,我想在出现对现有源的引用时停止
create table #temp (source int, destination int);
insert into #temp values (1,3), (3,7), (7,9), (9,1);
WITH cte (Source, Destination, Level, Sources)
AS
(
SELECT Source, Destination, 0 AS Level, CAST(Source AS VARCHAR(MAX)) + ',' AS Sources
FROM #temp
WHERE [Source] = 1
UNION ALL
SELECT t.[Source], t.Destination, cte.[Level] + 1, cte.Sources + CAST(t.Source AS VARCHAR(MAX)) + ','
FROM #temp t
INNER JOIN cte ON cte.Destination = t.[Source] AND (CAST(t.Destination AS VARCHAR(MAX)) + ',' NOT LIKE '%' + cte.Sources + '%')
)
select * from cte
drop table #temp;
然而,当 运行 这个时,我仍然得到最大递归错误。我应该如何正确编写保护条款?我想要的是前 3 个结果。
在 CTE 的递归部分添加 where
子句。
create table #temp (source int, destination int);
insert into #temp values (1,3), (3,7), (7,9), (9,1);
WITH cte (Source, Destination, Level, Sources)
AS
(
SELECT Source, Destination, 0 AS Level, CAST(Source AS VARCHAR(MAX)) + ',' AS Sources
FROM #temp
WHERE [Source] = 1
UNION ALL
SELECT t.[Source], t.Destination, cte.[Level] + 1, cte.Sources + CAST(t.Source AS VARCHAR(MAX)) + ','
FROM #temp t
INNER JOIN cte ON cte.Destination = t.[Source] AND (CAST(t.Destination AS VARCHAR(MAX)) + ',' NOT LIKE '%' + cte.Sources + '%')
where cte.Level < 2 -- stop after 3 levels (0,1,2)
)
select * from cte
drop table #temp;
这里,在CTE的递归成员中:
INNER JOIN cte
ON cte.Destination = t.[Source]
AND (CAST(t.Destination AS VARCHAR(MAX)) + ',' NOT LIKE '%' + cte.Sources + '%')
您的 LIKE
操作数是错误的。相反:
INNER JOIN cte
ON cte.Destination = t.[Source]
AND cte.Sources NOT LIKE CONCAT('%', t.Destination, '%')
即:目的地应该属于已经访问过的来源列表。请注意,使用 CONCAT()
会强制将数字转换为字符串,从而缩短表达式。