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









share|improve this question























  • 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














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









share|improve this question























  • 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












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









share|improve this question















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






sql-server common-table-expression recursive-query






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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
















  • 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












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





share|improve this answer








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

















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.



enter image description here



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.






share|improve this answer




















    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













     

    draft saved


    draft discarded


















    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






























    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





    share|improve this answer








    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














    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





    share|improve this answer








    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












    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





    share|improve this answer








    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






    share|improve this answer








    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.









    share|improve this answer



    share|improve this answer






    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
















    • 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












    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.



    enter image description here



    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.






    share|improve this answer
























      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.



      enter image description here



      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.






      share|improve this answer






















        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.



        enter image description here



        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.






        share|improve this answer












        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.



        enter image description here



        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.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 9 at 15:45









        pwilcox

        478212




        478212



























             

            draft saved


            draft discarded















































             


            draft saved


            draft discarded














            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














































































            Popular posts from this blog

            Darth Vader #20

            How to how show current date and time by default on contact form 7 in WordPress without taking input from user in datetimepicker

            Ondo