排除自引用元素递归 cte
exclude self-referencing elements recursive cte
我正在创建一个递归 CTE,因为我需要创建组合的层次结构。
当我 FROM
引用回 TO
时遇到问题。然后它无限循环并达到最大递归限制。我可以在 Levels 上设置一个 where 子句,但是我可能不会得到正确的数据,因为我的树可以是 x levels deeps
我的数据可能是这样的
From To Total Type
98579 10406 82 B
98579 17005 5834 S
98579 18879 6323 S
98579 18889 215 S
10406 43594 234 B
10406 73959 10 B
10406 98579 22824 B
43594 83827 4 S
43594 38475 543 S
正如您在数据中看到的那样,98579 命中 10406 并且 vise verca。
我的 cte 现在看起来像这样:
;WITH x AS
(
-- anchor:
SELECT b.[From]
,b.[To]
,b.[Total]
,b.[Type]
,0 as levels
FROM [dbo].[Test] b
where b.[FROM]= 98579
UNION ALL
-- recursive:
SELECT tm.[FROM], tm.[TO], tm.[Total], tm.[Type],levels +1
FROM [dbo].[Test] AS tm INNER JOIN x
ON x.TO= tm.FROM
--where levels <= 1
)
SELECT *FROM x
order by levels
我能做什么?
如果我理解正确的话,你只是想在递归回到开始的地方后终止它。
一个选项是添加一个像 StartPoint
这样的列或任何您想调用的列,然后在 where 子句中使用它来终止递归或过滤掉那些。
在不知道具体你想要的输出是什么的情况下,我根据示例数据假设这就是你想要的,代码中添加了注释:
DECLARE @TestData TABLE
(
[From] INT
, [To] INT
, [Total] INT
, [type] CHAR(1)
);
INSERT INTO @TestData (
[From]
, [To]
, [Total]
, [type]
)
VALUES ( 98579, 10406, 82, 'B' ) , ( 98579, 17005, 5834, 'S' ) , ( 98579, 18879, 6323, 'S' ) , ( 98579, 18889, 215, 'S' ) , ( 10406, 43594, 234, 'B' ) , ( 10406, 73959, 10, 'B' ) , ( 10406, 98579, 22824, 'B' ) , ( 43594, 83827, 4, 'S' ) , ( 43594, 38475, 543, 'S' );
WITH [x]
AS (
-- anchor:
SELECT [b].[From] AS [StartPoint] --Where are we starting
, [b].[From]
, [b].[To]
, [b].[Total]
, [b].[type]
, 0 AS [levels]
FROM @TestData [b]
WHERE [b].[From] = 98579
UNION ALL
-- recursive:
SELECT [x].[StartPoint] --Add it here
, [tm].[From]
, [tm].[To]
, [tm].[Total]
, [tm].[type]
, [x].[levels] + 1
FROM @TestData AS [tm]
INNER JOIN [x]
ON [x].[To] = [tm].[From]
WHERE [x].[StartPoint] <> [tm].[From] --stop the recursion once we have come back to where it started, filter those out.
)
SELECT [x].[From]
, [x].[To]
, [x].[Total]
, [x].[type]
, [x].[levels]
FROM [x]
ORDER BY [x].[levels];
给出结果:
From To Total type levels
----------- ----------- ----------- ---- -----------
98579 10406 82 B 0
98579 17005 5834 S 0
98579 18879 6323 S 0
98579 18889 215 S 0
10406 43594 234 B 1
10406 73959 10 B 1
10406 98579 22824 B 1
43594 83827 4 S 2
43594 38475 543 S 2
在这个例子中,我包括了你添加过滤器的地方 WHERE [b].[From] = 98579
不清楚这是为了显示循环引用的例子,还是你这样做是为了表明你的起点。
如果您删除上面代码中的 where 子句,它将提供所有内容。基本上每一行都考虑 StartPoint
并且您将获得每一行的所有重复,但是一旦它回到开始的位置就会 stop/filter :
给你:
From To Total type levels
----------- ----------- ----------- ---- -----------
98579 10406 82 B 0
98579 17005 5834 S 0
98579 18879 6323 S 0
98579 18889 215 S 0
10406 43594 234 B 0
10406 73959 10 B 0
10406 98579 22824 B 0
43594 83827 4 S 0
43594 38475 543 S 0
98579 10406 82 B 1
98579 17005 5834 S 1
98579 18879 6323 S 1
98579 18889 215 S 1
43594 83827 4 S 1
43594 38475 543 S 1
10406 43594 234 B 1
10406 73959 10 B 1
10406 98579 22824 B 1
43594 83827 4 S 2
43594 38475 543 S 2
我正在创建一个递归 CTE,因为我需要创建组合的层次结构。
当我 FROM
引用回 TO
时遇到问题。然后它无限循环并达到最大递归限制。我可以在 Levels 上设置一个 where 子句,但是我可能不会得到正确的数据,因为我的树可以是 x levels deeps
我的数据可能是这样的
From To Total Type
98579 10406 82 B
98579 17005 5834 S
98579 18879 6323 S
98579 18889 215 S
10406 43594 234 B
10406 73959 10 B
10406 98579 22824 B
43594 83827 4 S
43594 38475 543 S
正如您在数据中看到的那样,98579 命中 10406 并且 vise verca。
我的 cte 现在看起来像这样:
;WITH x AS
(
-- anchor:
SELECT b.[From]
,b.[To]
,b.[Total]
,b.[Type]
,0 as levels
FROM [dbo].[Test] b
where b.[FROM]= 98579
UNION ALL
-- recursive:
SELECT tm.[FROM], tm.[TO], tm.[Total], tm.[Type],levels +1
FROM [dbo].[Test] AS tm INNER JOIN x
ON x.TO= tm.FROM
--where levels <= 1
)
SELECT *FROM x
order by levels
我能做什么?
如果我理解正确的话,你只是想在递归回到开始的地方后终止它。
一个选项是添加一个像 StartPoint
这样的列或任何您想调用的列,然后在 where 子句中使用它来终止递归或过滤掉那些。
在不知道具体你想要的输出是什么的情况下,我根据示例数据假设这就是你想要的,代码中添加了注释:
DECLARE @TestData TABLE
(
[From] INT
, [To] INT
, [Total] INT
, [type] CHAR(1)
);
INSERT INTO @TestData (
[From]
, [To]
, [Total]
, [type]
)
VALUES ( 98579, 10406, 82, 'B' ) , ( 98579, 17005, 5834, 'S' ) , ( 98579, 18879, 6323, 'S' ) , ( 98579, 18889, 215, 'S' ) , ( 10406, 43594, 234, 'B' ) , ( 10406, 73959, 10, 'B' ) , ( 10406, 98579, 22824, 'B' ) , ( 43594, 83827, 4, 'S' ) , ( 43594, 38475, 543, 'S' );
WITH [x]
AS (
-- anchor:
SELECT [b].[From] AS [StartPoint] --Where are we starting
, [b].[From]
, [b].[To]
, [b].[Total]
, [b].[type]
, 0 AS [levels]
FROM @TestData [b]
WHERE [b].[From] = 98579
UNION ALL
-- recursive:
SELECT [x].[StartPoint] --Add it here
, [tm].[From]
, [tm].[To]
, [tm].[Total]
, [tm].[type]
, [x].[levels] + 1
FROM @TestData AS [tm]
INNER JOIN [x]
ON [x].[To] = [tm].[From]
WHERE [x].[StartPoint] <> [tm].[From] --stop the recursion once we have come back to where it started, filter those out.
)
SELECT [x].[From]
, [x].[To]
, [x].[Total]
, [x].[type]
, [x].[levels]
FROM [x]
ORDER BY [x].[levels];
给出结果:
From To Total type levels
----------- ----------- ----------- ---- -----------
98579 10406 82 B 0
98579 17005 5834 S 0
98579 18879 6323 S 0
98579 18889 215 S 0
10406 43594 234 B 1
10406 73959 10 B 1
10406 98579 22824 B 1
43594 83827 4 S 2
43594 38475 543 S 2
在这个例子中,我包括了你添加过滤器的地方 WHERE [b].[From] = 98579
不清楚这是为了显示循环引用的例子,还是你这样做是为了表明你的起点。
如果您删除上面代码中的 where 子句,它将提供所有内容。基本上每一行都考虑 StartPoint
并且您将获得每一行的所有重复,但是一旦它回到开始的位置就会 stop/filter :
给你:
From To Total type levels
----------- ----------- ----------- ---- -----------
98579 10406 82 B 0
98579 17005 5834 S 0
98579 18879 6323 S 0
98579 18889 215 S 0
10406 43594 234 B 0
10406 73959 10 B 0
10406 98579 22824 B 0
43594 83827 4 S 0
43594 38475 543 S 0
98579 10406 82 B 1
98579 17005 5834 S 1
98579 18879 6323 S 1
98579 18889 215 S 1
43594 83827 4 S 1
43594 38475 543 S 1
10406 43594 234 B 1
10406 73959 10 B 1
10406 98579 22824 B 1
43594 83827 4 S 2
43594 38475 543 S 2