Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Displaying sorted hierarchy rows in SQL server?

Assuming I have this table : ( c is a child of parent p)

c   p
------
40  0
2   3
2   40
3   1
7   2
1   0

Where (0 means root) — I want the order of select to be displayed as :

c   b
------
1   0
3   1
2   3
40  0
2   40
7   2

That's becuase we have 2 roots (1,40) and 1 < 40.

So we start at 1 and then display below it - all it's descendants.

Then we get to 40. same logic again.

enter image description here

Question:

How can I do it ?

I've succeeded to display it recursively + finding level of hierarchy*(not sure if it helps though)*

WITH cte(c, p) AS (
     SELECT 40, 0 UNION ALL
     SELECT 2,3 UNION ALL
     SELECT 2,40 UNION ALL
     SELECT 3,1 UNION ALL
     SELECT 7,2 UNION ALL   
     SELECT 1,0
     ) , cte2 AS(
         SELECT c,
                p,
                PLevel = 1
         FROM   cte
         WHERE  p = 0
         UNION ALL
         SELECT cte.c,
                cte.p,
                PLevel = cte2.PLevel + 1
         FROM   cte
                INNER JOIN cte2
                     ON  cte2.c = cte.p
     )

SELECT *
FROM   cte2

Full SQL fiddle

like image 574
Royi Namir Avatar asked Aug 05 '15 10:08

Royi Namir


People also ask

How do you display hierarchy?

Right-click the hierarchy that you want to change, and then click Change Layout. Click Hierarchy, and then do one of the following: To show hierarchical relationships progressing from top to bottom and grouped hierarchically, click Labeled Hierarchy.

How do I find the hierarchy in SQL Server?

Use hierarchyid as a data type to create tables with a hierarchical structure, or to describe the hierarchical structure of data that is stored in another location. Use the hierarchyid functions in Transact-SQL to query and manage hierarchical data.


1 Answers

You have almost done it. Just add a rank to identify each group and then sort the data on it.

Also, as you are working with more complex hierarchy we need to change the [level] value. In is now not a number, put the full path of the current element to its parent. Where \ means parent. For example the following string:

\1\5\4\1

represents the hierarchy below:

   1
   --> 5
       --> 4
           --> 1

I get the idea from hierarchyid type. You may want to consider storing hierarchies using it, as it has handy build-in functions for working with such structures.


Here is full working example with the new data:

DECLARE @DataSource TABLE
(
    [c] TINYINT
   ,[p] TINYINT
);

INSERT INTO @DataSource ([c], [p])
VALUES (1,0)
      ,(3, 1)
      ,(2, 3)
      ,(5,1)
      ,(7, 2)
      ,(40, 0)
      ,(2, 40);

WITH DataSource ([c], [p], [level], [rank])AS
(
    SELECT [c]
          ,[p]
          ,CAST('/' AS VARCHAR(24))
          ,ROW_NUMBER() OVER (ORDER BY [c] ASC)
    FROM  @DataSource
    WHERE [p] = 0
    UNION ALL
    SELECT DS.[c]
          ,DS.[p]
          ,CAST(DS1.[level] + CAST(DS.[c] AS VARCHAR(3)) + '/' AS VARCHAR(24))
          ,DS1.[rank]
    FROM  @DataSource DS
    INNER JOIN DataSource DS1
        ON  DS1.[c] = DS.[p]
)
SELECT [c]
      ,[p]
FROM DataSource
ORDER BY [Rank]
        ,CAST([level] AS hierarchyid);

enter image description here

Again, pay attention to the node (7,2) which is participating in the two groups (even in your example). I guess this is just a sample data and you have a way to defined where the node should be included.

like image 51
gotqn Avatar answered Oct 15 '22 14:10

gotqn