Find a specific parent inside hierarchical data using T-SQL











up vote
4
down vote

favorite












I've got objects with an hierarchical order. Each object has an ID, a parent object (TO_ID in the table) and a type.
My data is in a table which looks like this:



ID  | TO_ID | TYPE
123 | 103 | group
176 | 103 | field
256 | 169 | group
103 | 234 | organization
234 | 390 | site


Now I want to search through the table until I find a parent object with a specific type (I don't know how many parent objects my have start object).



For example I start with ID 123 and want to find the ID of the parent object with TYPE site.



How can I solve this with SQL?










share|improve this question




























    up vote
    4
    down vote

    favorite












    I've got objects with an hierarchical order. Each object has an ID, a parent object (TO_ID in the table) and a type.
    My data is in a table which looks like this:



    ID  | TO_ID | TYPE
    123 | 103 | group
    176 | 103 | field
    256 | 169 | group
    103 | 234 | organization
    234 | 390 | site


    Now I want to search through the table until I find a parent object with a specific type (I don't know how many parent objects my have start object).



    For example I start with ID 123 and want to find the ID of the parent object with TYPE site.



    How can I solve this with SQL?










    share|improve this question


























      up vote
      4
      down vote

      favorite









      up vote
      4
      down vote

      favorite











      I've got objects with an hierarchical order. Each object has an ID, a parent object (TO_ID in the table) and a type.
      My data is in a table which looks like this:



      ID  | TO_ID | TYPE
      123 | 103 | group
      176 | 103 | field
      256 | 169 | group
      103 | 234 | organization
      234 | 390 | site


      Now I want to search through the table until I find a parent object with a specific type (I don't know how many parent objects my have start object).



      For example I start with ID 123 and want to find the ID of the parent object with TYPE site.



      How can I solve this with SQL?










      share|improve this question















      I've got objects with an hierarchical order. Each object has an ID, a parent object (TO_ID in the table) and a type.
      My data is in a table which looks like this:



      ID  | TO_ID | TYPE
      123 | 103 | group
      176 | 103 | field
      256 | 169 | group
      103 | 234 | organization
      234 | 390 | site


      Now I want to search through the table until I find a parent object with a specific type (I don't know how many parent objects my have start object).



      For example I start with ID 123 and want to find the ID of the parent object with TYPE site.



      How can I solve this with SQL?







      sql sql-server tsql hierarchical-data






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited 3 hours ago









      Salman A

      169k65327413




      169k65327413










      asked 4 hours ago









      Ramona

      496




      496
























          1 Answer
          1






          active

          oldest

          votes

















          up vote
          4
          down vote



          accepted










          You need a recursive CTE for this:



          DECLARE @t TABLE (ID INT, TO_ID INT, TYPE VARCHAR(100));

          INSERT INTO @t VALUES
          (123, 103, 'group'),
          (176, 103, 'field'),
          (256, 169, 'group'),
          (103, 234, 'organization'),
          (234, 390, 'site'),
          (390, 999, 'notme');

          DECLARE @start INT = 123;
          DECLARE @stop VARCHAR(100) = 'site';

          WITH cte AS (
          SELECT base.*, 1 AS LVL
          FROM @t base
          WHERE ID = @start
          UNION ALL
          SELECT curr.*, LVL + 1
          FROM @t curr
          INNER JOIN cte prev ON curr.ID = prev.TO_ID
          WHERE prev.TYPE <> @stop
          )
          SELECT *
          FROM cte
          ORDER BY LVL


          A recursive CTE is actually an iterative query. You start with some rows (the 123 row) and then you keep appending rows to the result of previous iteration until some criteria is met (you run out of rows or found site in the previous iteration). Here is the result:



          ID  | TO_ID | TYPE         | LVL
          123 | 103 | group | 1
          103 | 234 | organization | 2
          234 | 390 | site | 3


          If you're not interested in finding the complete path between the two nodes then remove the where clause from curr and add WHERE TYPE = site at the very end.






          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%2f53203301%2ffind-a-specific-parent-inside-hierarchical-data-using-t-sql%23new-answer', 'question_page');
            }
            );

            Post as a guest
































            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            4
            down vote



            accepted










            You need a recursive CTE for this:



            DECLARE @t TABLE (ID INT, TO_ID INT, TYPE VARCHAR(100));

            INSERT INTO @t VALUES
            (123, 103, 'group'),
            (176, 103, 'field'),
            (256, 169, 'group'),
            (103, 234, 'organization'),
            (234, 390, 'site'),
            (390, 999, 'notme');

            DECLARE @start INT = 123;
            DECLARE @stop VARCHAR(100) = 'site';

            WITH cte AS (
            SELECT base.*, 1 AS LVL
            FROM @t base
            WHERE ID = @start
            UNION ALL
            SELECT curr.*, LVL + 1
            FROM @t curr
            INNER JOIN cte prev ON curr.ID = prev.TO_ID
            WHERE prev.TYPE <> @stop
            )
            SELECT *
            FROM cte
            ORDER BY LVL


            A recursive CTE is actually an iterative query. You start with some rows (the 123 row) and then you keep appending rows to the result of previous iteration until some criteria is met (you run out of rows or found site in the previous iteration). Here is the result:



            ID  | TO_ID | TYPE         | LVL
            123 | 103 | group | 1
            103 | 234 | organization | 2
            234 | 390 | site | 3


            If you're not interested in finding the complete path between the two nodes then remove the where clause from curr and add WHERE TYPE = site at the very end.






            share|improve this answer



























              up vote
              4
              down vote



              accepted










              You need a recursive CTE for this:



              DECLARE @t TABLE (ID INT, TO_ID INT, TYPE VARCHAR(100));

              INSERT INTO @t VALUES
              (123, 103, 'group'),
              (176, 103, 'field'),
              (256, 169, 'group'),
              (103, 234, 'organization'),
              (234, 390, 'site'),
              (390, 999, 'notme');

              DECLARE @start INT = 123;
              DECLARE @stop VARCHAR(100) = 'site';

              WITH cte AS (
              SELECT base.*, 1 AS LVL
              FROM @t base
              WHERE ID = @start
              UNION ALL
              SELECT curr.*, LVL + 1
              FROM @t curr
              INNER JOIN cte prev ON curr.ID = prev.TO_ID
              WHERE prev.TYPE <> @stop
              )
              SELECT *
              FROM cte
              ORDER BY LVL


              A recursive CTE is actually an iterative query. You start with some rows (the 123 row) and then you keep appending rows to the result of previous iteration until some criteria is met (you run out of rows or found site in the previous iteration). Here is the result:



              ID  | TO_ID | TYPE         | LVL
              123 | 103 | group | 1
              103 | 234 | organization | 2
              234 | 390 | site | 3


              If you're not interested in finding the complete path between the two nodes then remove the where clause from curr and add WHERE TYPE = site at the very end.






              share|improve this answer

























                up vote
                4
                down vote



                accepted







                up vote
                4
                down vote



                accepted






                You need a recursive CTE for this:



                DECLARE @t TABLE (ID INT, TO_ID INT, TYPE VARCHAR(100));

                INSERT INTO @t VALUES
                (123, 103, 'group'),
                (176, 103, 'field'),
                (256, 169, 'group'),
                (103, 234, 'organization'),
                (234, 390, 'site'),
                (390, 999, 'notme');

                DECLARE @start INT = 123;
                DECLARE @stop VARCHAR(100) = 'site';

                WITH cte AS (
                SELECT base.*, 1 AS LVL
                FROM @t base
                WHERE ID = @start
                UNION ALL
                SELECT curr.*, LVL + 1
                FROM @t curr
                INNER JOIN cte prev ON curr.ID = prev.TO_ID
                WHERE prev.TYPE <> @stop
                )
                SELECT *
                FROM cte
                ORDER BY LVL


                A recursive CTE is actually an iterative query. You start with some rows (the 123 row) and then you keep appending rows to the result of previous iteration until some criteria is met (you run out of rows or found site in the previous iteration). Here is the result:



                ID  | TO_ID | TYPE         | LVL
                123 | 103 | group | 1
                103 | 234 | organization | 2
                234 | 390 | site | 3


                If you're not interested in finding the complete path between the two nodes then remove the where clause from curr and add WHERE TYPE = site at the very end.






                share|improve this answer














                You need a recursive CTE for this:



                DECLARE @t TABLE (ID INT, TO_ID INT, TYPE VARCHAR(100));

                INSERT INTO @t VALUES
                (123, 103, 'group'),
                (176, 103, 'field'),
                (256, 169, 'group'),
                (103, 234, 'organization'),
                (234, 390, 'site'),
                (390, 999, 'notme');

                DECLARE @start INT = 123;
                DECLARE @stop VARCHAR(100) = 'site';

                WITH cte AS (
                SELECT base.*, 1 AS LVL
                FROM @t base
                WHERE ID = @start
                UNION ALL
                SELECT curr.*, LVL + 1
                FROM @t curr
                INNER JOIN cte prev ON curr.ID = prev.TO_ID
                WHERE prev.TYPE <> @stop
                )
                SELECT *
                FROM cte
                ORDER BY LVL


                A recursive CTE is actually an iterative query. You start with some rows (the 123 row) and then you keep appending rows to the result of previous iteration until some criteria is met (you run out of rows or found site in the previous iteration). Here is the result:



                ID  | TO_ID | TYPE         | LVL
                123 | 103 | group | 1
                103 | 234 | organization | 2
                234 | 390 | site | 3


                If you're not interested in finding the complete path between the two nodes then remove the where clause from curr and add WHERE TYPE = site at the very end.







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited 3 hours ago

























                answered 3 hours ago









                Salman A

                169k65327413




                169k65327413






























                     

                    draft saved


                    draft discarded



















































                     


                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53203301%2ffind-a-specific-parent-inside-hierarchical-data-using-t-sql%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest




















































































                    Popular posts from this blog

                    Landwehr

                    Reims

                    Javascript gets undefined on array