cte recursive part only returns one row
up vote
2
down vote
favorite
If I don't have a join in the recursive part of my CTE, I only get one row per recursion, why is that?
Code tested on SQL Server 2016 and Azure SQL database:
DECLARE @Number TABLE (Number INT);
INSERT INTO @Number (Number)
VALUES (1), (2);
;WITH _cte AS
(
SELECT Number
FROM @Number
UNION ALL
SELECT _cte.Number
FROM _cte
)
SELECT *
FROM _cte
OPTION (MAXRECURSION 2); -- just call recursive part twice to see the issue
In the result I get number 2
in each recursion/depth.
I would expect the current rows to be repeated in each recursion, hence an exponential increase in the number of rows
Expected output
Number
--------------------
1 -- from anchor
2
1 -- first recursion
2
1 -- second recursion
2
1
2
Actual output:
Number
--------------------
1 -- from anchor
2
2 -- first recursion
2 -- second recursion
![](http://i.stack.imgur.com/gfrSH.png)
add a comment |
up vote
2
down vote
favorite
If I don't have a join in the recursive part of my CTE, I only get one row per recursion, why is that?
Code tested on SQL Server 2016 and Azure SQL database:
DECLARE @Number TABLE (Number INT);
INSERT INTO @Number (Number)
VALUES (1), (2);
;WITH _cte AS
(
SELECT Number
FROM @Number
UNION ALL
SELECT _cte.Number
FROM _cte
)
SELECT *
FROM _cte
OPTION (MAXRECURSION 2); -- just call recursive part twice to see the issue
In the result I get number 2
in each recursion/depth.
I would expect the current rows to be repeated in each recursion, hence an exponential increase in the number of rows
Expected output
Number
--------------------
1 -- from anchor
2
1 -- first recursion
2
1 -- second recursion
2
1
2
Actual output:
Number
--------------------
1 -- from anchor
2
2 -- first recursion
2 -- second recursion
![](http://i.stack.imgur.com/gfrSH.png)
That code, as written, would throw an error.
– scsimon
Nov 9 at 15:37
1
blogs.msdn.microsoft.com/craigfr/2007/10/25/recursive-ctes
– Martin Smith
Nov 9 at 17:20
Thanks @MartinSmith - that link confirmed what I suspected with my answer. The order of the results as I was trying different queries looked like a stack with results pushed in order and the last item on the stack popped for recursion and the post you linked confirmed that SQL Server really does work that way internally.
– Shawn Pence
Nov 9 at 19:27
add a comment |
up vote
2
down vote
favorite
up vote
2
down vote
favorite
If I don't have a join in the recursive part of my CTE, I only get one row per recursion, why is that?
Code tested on SQL Server 2016 and Azure SQL database:
DECLARE @Number TABLE (Number INT);
INSERT INTO @Number (Number)
VALUES (1), (2);
;WITH _cte AS
(
SELECT Number
FROM @Number
UNION ALL
SELECT _cte.Number
FROM _cte
)
SELECT *
FROM _cte
OPTION (MAXRECURSION 2); -- just call recursive part twice to see the issue
In the result I get number 2
in each recursion/depth.
I would expect the current rows to be repeated in each recursion, hence an exponential increase in the number of rows
Expected output
Number
--------------------
1 -- from anchor
2
1 -- first recursion
2
1 -- second recursion
2
1
2
Actual output:
Number
--------------------
1 -- from anchor
2
2 -- first recursion
2 -- second recursion
![](http://i.stack.imgur.com/gfrSH.png)
If I don't have a join in the recursive part of my CTE, I only get one row per recursion, why is that?
Code tested on SQL Server 2016 and Azure SQL database:
DECLARE @Number TABLE (Number INT);
INSERT INTO @Number (Number)
VALUES (1), (2);
;WITH _cte AS
(
SELECT Number
FROM @Number
UNION ALL
SELECT _cte.Number
FROM _cte
)
SELECT *
FROM _cte
OPTION (MAXRECURSION 2); -- just call recursive part twice to see the issue
In the result I get number 2
in each recursion/depth.
I would expect the current rows to be repeated in each recursion, hence an exponential increase in the number of rows
Expected output
Number
--------------------
1 -- from anchor
2
1 -- first recursion
2
1 -- second recursion
2
1
2
Actual output:
Number
--------------------
1 -- from anchor
2
2 -- first recursion
2 -- second recursion
![](http://i.stack.imgur.com/gfrSH.png)
![](http://i.stack.imgur.com/gfrSH.png)
edited Nov 9 at 15:22
marc_s
564k12510891242
564k12510891242
asked Nov 9 at 15:16
Nisar Yaqoob
161
161
That code, as written, would throw an error.
– scsimon
Nov 9 at 15:37
1
blogs.msdn.microsoft.com/craigfr/2007/10/25/recursive-ctes
– Martin Smith
Nov 9 at 17:20
Thanks @MartinSmith - that link confirmed what I suspected with my answer. The order of the results as I was trying different queries looked like a stack with results pushed in order and the last item on the stack popped for recursion and the post you linked confirmed that SQL Server really does work that way internally.
– Shawn Pence
Nov 9 at 19:27
add a comment |
That code, as written, would throw an error.
– scsimon
Nov 9 at 15:37
1
blogs.msdn.microsoft.com/craigfr/2007/10/25/recursive-ctes
– Martin Smith
Nov 9 at 17:20
Thanks @MartinSmith - that link confirmed what I suspected with my answer. The order of the results as I was trying different queries looked like a stack with results pushed in order and the last item on the stack popped for recursion and the post you linked confirmed that SQL Server really does work that way internally.
– Shawn Pence
Nov 9 at 19:27
That code, as written, would throw an error.
– scsimon
Nov 9 at 15:37
That code, as written, would throw an error.
– scsimon
Nov 9 at 15:37
1
1
blogs.msdn.microsoft.com/craigfr/2007/10/25/recursive-ctes
– Martin Smith
Nov 9 at 17:20
blogs.msdn.microsoft.com/craigfr/2007/10/25/recursive-ctes
– Martin Smith
Nov 9 at 17:20
Thanks @MartinSmith - that link confirmed what I suspected with my answer. The order of the results as I was trying different queries looked like a stack with results pushed in order and the last item on the stack popped for recursion and the post you linked confirmed that SQL Server really does work that way internally.
– Shawn Pence
Nov 9 at 19:27
Thanks @MartinSmith - that link confirmed what I suspected with my answer. The order of the results as I was trying different queries looked like a stack with results pushed in order and the last item on the stack popped for recursion and the post you linked confirmed that SQL Server really does work that way internally.
– Shawn Pence
Nov 9 at 19:27
add a comment |
2 Answers
2
active
oldest
votes
up vote
2
down vote
From some testing, it appears that SQL recursion occurs depth first beginning with the last row returned from the initial query. As soon as it has reached MAXRECURSION
, the query terminates with an error (e.g. The statement terminated. The maximum recursion 2 has been exhausted before statement completion.
) and returns whatever results it reached before the error. You can verify this by inserting 2,1 instead of 1,2 in your insert statement, or by inserting 1,2,3 into your @Number
table. If you insert 1,2,3 into @Number
, your results returned would be
1 -- From anchor
2 -- From anchor
3 -- From anchor
3 -- 1st recursion from last row of anchor query
3 -- Recursion from the row from the line above this (2nd recursion)
-- Query terminates after MAXRECURSION reached on an item and does not attempt recursion on 1 or 2
Typically, when using recursion, you join the CTE to itself or some other table with some criteria in the where statement or the on criteria in the join that would limit the recursion based on the available data (not just repeated recursion through the same elements). For example (using the same @Number
table from your question):
DECLARE @Number TABLE (Number INT);
INSERT @Number
(
Number
)
VALUES (1),
(2);
WITH _cte2
AS
(SELECT
Number
,0 as 'RecursionCount'
FROM
@Number
UNION ALL
SELECT
Number
,RecursionCount + 1
FROM
_cte2
WHERE
RecursionCount <= 1
)
SELECT * FROM _cte2 OPTION (MAXRECURSION 2);
In the above example, the query will limit its own recursion in the where statement and never reach MAXRECURSION, so the query will be able to finish. You'll also note that the order of results returned confirms my suspicion that recursion is depth first beginning with the last item:
Number RecursionCount
1 0
2 0
2 1
2 2
1 1
1 2
New contributor
Shawn Pence is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
Hat's off to you Shawn. You put the explanation to the ordering oddity I found.
– pwilcox
Nov 9 at 15:55
add a comment |
up vote
0
down vote
I changed your code a bit to this:
with
_cte as (
SELECT num, 0 iteration
FROM @Number
UNION ALL
SELECT num, iteration + 1
FROM _cte
where iteration <= 3 -- comment this line out and compare
)
SELECT *
FROM _cte
--OPTION (MAXRECURSION 2); -- comment this line out and compare as well
I then compared the results with that when commenting out the 'where iteration <= 3'. It took me awhile to realize, but the ordering of the results were not what I expected.
I think that when the error for max loops hits, or when you put in the option to cut off the max recursion, it is somehow cutting off the latter results that you would find in rows 7-10.
add a comment |
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
2
down vote
From some testing, it appears that SQL recursion occurs depth first beginning with the last row returned from the initial query. As soon as it has reached MAXRECURSION
, the query terminates with an error (e.g. The statement terminated. The maximum recursion 2 has been exhausted before statement completion.
) and returns whatever results it reached before the error. You can verify this by inserting 2,1 instead of 1,2 in your insert statement, or by inserting 1,2,3 into your @Number
table. If you insert 1,2,3 into @Number
, your results returned would be
1 -- From anchor
2 -- From anchor
3 -- From anchor
3 -- 1st recursion from last row of anchor query
3 -- Recursion from the row from the line above this (2nd recursion)
-- Query terminates after MAXRECURSION reached on an item and does not attempt recursion on 1 or 2
Typically, when using recursion, you join the CTE to itself or some other table with some criteria in the where statement or the on criteria in the join that would limit the recursion based on the available data (not just repeated recursion through the same elements). For example (using the same @Number
table from your question):
DECLARE @Number TABLE (Number INT);
INSERT @Number
(
Number
)
VALUES (1),
(2);
WITH _cte2
AS
(SELECT
Number
,0 as 'RecursionCount'
FROM
@Number
UNION ALL
SELECT
Number
,RecursionCount + 1
FROM
_cte2
WHERE
RecursionCount <= 1
)
SELECT * FROM _cte2 OPTION (MAXRECURSION 2);
In the above example, the query will limit its own recursion in the where statement and never reach MAXRECURSION, so the query will be able to finish. You'll also note that the order of results returned confirms my suspicion that recursion is depth first beginning with the last item:
Number RecursionCount
1 0
2 0
2 1
2 2
1 1
1 2
New contributor
Shawn Pence is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
Hat's off to you Shawn. You put the explanation to the ordering oddity I found.
– pwilcox
Nov 9 at 15:55
add a comment |
up vote
2
down vote
From some testing, it appears that SQL recursion occurs depth first beginning with the last row returned from the initial query. As soon as it has reached MAXRECURSION
, the query terminates with an error (e.g. The statement terminated. The maximum recursion 2 has been exhausted before statement completion.
) and returns whatever results it reached before the error. You can verify this by inserting 2,1 instead of 1,2 in your insert statement, or by inserting 1,2,3 into your @Number
table. If you insert 1,2,3 into @Number
, your results returned would be
1 -- From anchor
2 -- From anchor
3 -- From anchor
3 -- 1st recursion from last row of anchor query
3 -- Recursion from the row from the line above this (2nd recursion)
-- Query terminates after MAXRECURSION reached on an item and does not attempt recursion on 1 or 2
Typically, when using recursion, you join the CTE to itself or some other table with some criteria in the where statement or the on criteria in the join that would limit the recursion based on the available data (not just repeated recursion through the same elements). For example (using the same @Number
table from your question):
DECLARE @Number TABLE (Number INT);
INSERT @Number
(
Number
)
VALUES (1),
(2);
WITH _cte2
AS
(SELECT
Number
,0 as 'RecursionCount'
FROM
@Number
UNION ALL
SELECT
Number
,RecursionCount + 1
FROM
_cte2
WHERE
RecursionCount <= 1
)
SELECT * FROM _cte2 OPTION (MAXRECURSION 2);
In the above example, the query will limit its own recursion in the where statement and never reach MAXRECURSION, so the query will be able to finish. You'll also note that the order of results returned confirms my suspicion that recursion is depth first beginning with the last item:
Number RecursionCount
1 0
2 0
2 1
2 2
1 1
1 2
New contributor
Shawn Pence is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
Hat's off to you Shawn. You put the explanation to the ordering oddity I found.
– pwilcox
Nov 9 at 15:55
add a comment |
up vote
2
down vote
up vote
2
down vote
From some testing, it appears that SQL recursion occurs depth first beginning with the last row returned from the initial query. As soon as it has reached MAXRECURSION
, the query terminates with an error (e.g. The statement terminated. The maximum recursion 2 has been exhausted before statement completion.
) and returns whatever results it reached before the error. You can verify this by inserting 2,1 instead of 1,2 in your insert statement, or by inserting 1,2,3 into your @Number
table. If you insert 1,2,3 into @Number
, your results returned would be
1 -- From anchor
2 -- From anchor
3 -- From anchor
3 -- 1st recursion from last row of anchor query
3 -- Recursion from the row from the line above this (2nd recursion)
-- Query terminates after MAXRECURSION reached on an item and does not attempt recursion on 1 or 2
Typically, when using recursion, you join the CTE to itself or some other table with some criteria in the where statement or the on criteria in the join that would limit the recursion based on the available data (not just repeated recursion through the same elements). For example (using the same @Number
table from your question):
DECLARE @Number TABLE (Number INT);
INSERT @Number
(
Number
)
VALUES (1),
(2);
WITH _cte2
AS
(SELECT
Number
,0 as 'RecursionCount'
FROM
@Number
UNION ALL
SELECT
Number
,RecursionCount + 1
FROM
_cte2
WHERE
RecursionCount <= 1
)
SELECT * FROM _cte2 OPTION (MAXRECURSION 2);
In the above example, the query will limit its own recursion in the where statement and never reach MAXRECURSION, so the query will be able to finish. You'll also note that the order of results returned confirms my suspicion that recursion is depth first beginning with the last item:
Number RecursionCount
1 0
2 0
2 1
2 2
1 1
1 2
New contributor
Shawn Pence is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
From some testing, it appears that SQL recursion occurs depth first beginning with the last row returned from the initial query. As soon as it has reached MAXRECURSION
, the query terminates with an error (e.g. The statement terminated. The maximum recursion 2 has been exhausted before statement completion.
) and returns whatever results it reached before the error. You can verify this by inserting 2,1 instead of 1,2 in your insert statement, or by inserting 1,2,3 into your @Number
table. If you insert 1,2,3 into @Number
, your results returned would be
1 -- From anchor
2 -- From anchor
3 -- From anchor
3 -- 1st recursion from last row of anchor query
3 -- Recursion from the row from the line above this (2nd recursion)
-- Query terminates after MAXRECURSION reached on an item and does not attempt recursion on 1 or 2
Typically, when using recursion, you join the CTE to itself or some other table with some criteria in the where statement or the on criteria in the join that would limit the recursion based on the available data (not just repeated recursion through the same elements). For example (using the same @Number
table from your question):
DECLARE @Number TABLE (Number INT);
INSERT @Number
(
Number
)
VALUES (1),
(2);
WITH _cte2
AS
(SELECT
Number
,0 as 'RecursionCount'
FROM
@Number
UNION ALL
SELECT
Number
,RecursionCount + 1
FROM
_cte2
WHERE
RecursionCount <= 1
)
SELECT * FROM _cte2 OPTION (MAXRECURSION 2);
In the above example, the query will limit its own recursion in the where statement and never reach MAXRECURSION, so the query will be able to finish. You'll also note that the order of results returned confirms my suspicion that recursion is depth first beginning with the last item:
Number RecursionCount
1 0
2 0
2 1
2 2
1 1
1 2
New contributor
Shawn Pence is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
New contributor
Shawn Pence is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
answered Nov 9 at 15:48
Shawn Pence
564
564
New contributor
Shawn Pence is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
New contributor
Shawn Pence is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
Shawn Pence is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
Hat's off to you Shawn. You put the explanation to the ordering oddity I found.
– pwilcox
Nov 9 at 15:55
add a comment |
Hat's off to you Shawn. You put the explanation to the ordering oddity I found.
– pwilcox
Nov 9 at 15:55
Hat's off to you Shawn. You put the explanation to the ordering oddity I found.
– pwilcox
Nov 9 at 15:55
Hat's off to you Shawn. You put the explanation to the ordering oddity I found.
– pwilcox
Nov 9 at 15:55
add a comment |
up vote
0
down vote
I changed your code a bit to this:
with
_cte as (
SELECT num, 0 iteration
FROM @Number
UNION ALL
SELECT num, iteration + 1
FROM _cte
where iteration <= 3 -- comment this line out and compare
)
SELECT *
FROM _cte
--OPTION (MAXRECURSION 2); -- comment this line out and compare as well
I then compared the results with that when commenting out the 'where iteration <= 3'. It took me awhile to realize, but the ordering of the results were not what I expected.
I think that when the error for max loops hits, or when you put in the option to cut off the max recursion, it is somehow cutting off the latter results that you would find in rows 7-10.
add a comment |
up vote
0
down vote
I changed your code a bit to this:
with
_cte as (
SELECT num, 0 iteration
FROM @Number
UNION ALL
SELECT num, iteration + 1
FROM _cte
where iteration <= 3 -- comment this line out and compare
)
SELECT *
FROM _cte
--OPTION (MAXRECURSION 2); -- comment this line out and compare as well
I then compared the results with that when commenting out the 'where iteration <= 3'. It took me awhile to realize, but the ordering of the results were not what I expected.
I think that when the error for max loops hits, or when you put in the option to cut off the max recursion, it is somehow cutting off the latter results that you would find in rows 7-10.
add a comment |
up vote
0
down vote
up vote
0
down vote
I changed your code a bit to this:
with
_cte as (
SELECT num, 0 iteration
FROM @Number
UNION ALL
SELECT num, iteration + 1
FROM _cte
where iteration <= 3 -- comment this line out and compare
)
SELECT *
FROM _cte
--OPTION (MAXRECURSION 2); -- comment this line out and compare as well
I then compared the results with that when commenting out the 'where iteration <= 3'. It took me awhile to realize, but the ordering of the results were not what I expected.
I think that when the error for max loops hits, or when you put in the option to cut off the max recursion, it is somehow cutting off the latter results that you would find in rows 7-10.
I changed your code a bit to this:
with
_cte as (
SELECT num, 0 iteration
FROM @Number
UNION ALL
SELECT num, iteration + 1
FROM _cte
where iteration <= 3 -- comment this line out and compare
)
SELECT *
FROM _cte
--OPTION (MAXRECURSION 2); -- comment this line out and compare as well
I then compared the results with that when commenting out the 'where iteration <= 3'. It took me awhile to realize, but the ordering of the results were not what I expected.
I think that when the error for max loops hits, or when you put in the option to cut off the max recursion, it is somehow cutting off the latter results that you would find in rows 7-10.
answered Nov 9 at 15:45
pwilcox
478212
478212
add a comment |
add a comment |
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53228439%2fcte-recursive-part-only-returns-one-row%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
That code, as written, would throw an error.
– scsimon
Nov 9 at 15:37
1
blogs.msdn.microsoft.com/craigfr/2007/10/25/recursive-ctes
– Martin Smith
Nov 9 at 17:20
Thanks @MartinSmith - that link confirmed what I suspected with my answer. The order of the results as I was trying different queries looked like a stack with results pushed in order and the last item on the stack popped for recursion and the post you linked confirmed that SQL Server really does work that way internally.
– Shawn Pence
Nov 9 at 19:27