Отображение отсортированных строк иерархии на SQL-сервере?

Предполагая, что у меня есть эта таблица: (c является дочерним от родительского p)

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

Где (0 означает root) - я хочу, чтобы порядок выбора отображался как:

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

Потому что у нас есть 2 корня (1,40) и 1 <40.

Итак, мы начинаем с 1 а затем отображаем под ним - все это потомки.

Тогда мы доберемся до 40. опять та же логика.

enter image description here

Вопрос:

Как мне это сделать?

Мне удалось отобразить его рекурсивно + поиск уровня иерархии * (хотя я не уверен, что это поможет) *

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

Полная скрипка SQL

Ответ 1

Ты почти сделал это. Просто добавьте rank, чтобы идентифицировать каждую группу, а затем отсортировать данные по ней.

Кроме того, поскольку вы работаете с более сложной иерархией, нам нужно изменить значение [level]. В настоящее время это не число, поместите полный путь текущего элемента в родительский. Где \ означает родительский. Например, следующая строка:

\ 1\5\4\1

представляет иерархию ниже:

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

Я получаю идею от hierarchyid. Вы можете захотеть сохранить иерархию, используя ее, так как она имеет удобные встроенные функции для работы с такими структурами.


Вот полный рабочий пример с новыми данными:

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);

введите описание изображения здесь

Снова обратите внимание на node (7,2), который участвует в двух группах (даже в вашем примере). Я думаю, это всего лишь образец данных, и у вас есть способ определить, где должен быть включен node.