확장 된 트리와 같은 방식으로 재귀 쿼리 결과를 어떻게 정렬합니까?


12

다음 nodes과 같은 테이블이 있다고 가정 해 봅시다 .

CREATE TABLE nodes
(
    node serial PRIMARY KEY,
    parent integer NULL REFERENCES nodes(node),
    ts timestamp NOT NULL DEFAULT now()
);

루트 노드가 최상위 노드에 있고 루트 노드 또는 다른 하위 노드에서 매달려있는 여러 하위 노드가있는 표준 노드 형 트리 구조를 나타냅니다.

몇 가지 예제 값을 삽입하겠습니다.

INSERT INTO nodes (parent)
VALUES (NULL), (NULL), (NULL), (NULL), (1), (1), (1), (1), (6), (1)
     , (6), (9), (6), (6), (3), (3), (3), (15);

이제 처음 10 개의 루트 노드와 모든 하위 노드를 4 단계까지 검색하려고합니다.

WITH RECURSIVE node_rec AS
(
    (SELECT 1 AS depth, * FROM nodes WHERE parent IS NULL LIMIT 10)

    UNION ALL

    SELECT depth + 1, n.*
    FROM nodes AS n JOIN node_rec ON (n.parent = node_rec.node)
    WHERE depth < 4
)
SELECT * FROM node_rec;

이것은 훌륭하게 작동하며 다음 결과를 제공합니다.

 depth | node | parent 
-------+------+--------
     1 |  1   |
     1 |  2   |
     1 |  3   |
     1 |  4   |
     2 |  5   |  1
     2 |  6   |  1
     2 |  7   |  1
     2 |  8   |  1
     2 | 10   |  1
     2 | 15   |  3
     2 | 16   |  3
     2 | 17   |  3
     3 |  9   |  6
     3 | 11   |  6
     3 | 13   |  6
     3 | 14   |  6
     3 | 18   | 15
     4 | 12   |  9

알다시피, ORDER BY절이 없으므로 순서가 정의되지 않았습니다. 여기서 보는 순서는 루트 노드에서 더 깊은 노드까지입니다.

아래 예제 그림에서 볼 수 있듯이 확장 된 트리보기에 표시되는 결과를 어떻게 주문합니까?

노드의 확장 트리 뷰

기본적으로 자식 노드가 해당 부모 노드 바로 뒤에 배치되기를 원합니다. 두 개 이상의 자식 노드에 동일한 부모 노드가 있으면 타임 스탬프별로 정렬하고 싶습니다. 위의 예를 바탕으로 달성하려는 원하는 출력 순서는 다음과 같습니다.

 depth | node | parent | ts
-------+------+--------+---------
     1 |  1   |        | 2014-01-01 00:00:00
     2 |  5   |     1  | 2014-01-01 00:10:00
     2 |  6   |     1  | 2014-01-01 00:20:00
     3 |  9   |     6  | 2014-01-01 00:25:00
     4 |  12  |     9  | 2014-01-01 00:27:00
     3 |  11  |     6  | 2014-01-01 00:26:00
     3 |  13  |     6  | 2014-01-01 00:30:00
     3 |  14  |     6  | 2014-01-01 00:36:00
     2 |  7   |     1  | 2014-01-01 00:21:00
     2 |  8   |     1  | 2014-01-01 00:22:00
     2 |  10  |     1  | 2014-01-01 00:23:00
     1 |  2   |        | 2014-01-01 00:08:00
     1 |  3   |        | 2014-01-01 00:09:00
     2 |  15  |     3  | 2014-01-01 10:00:00
     3 |  18  |     15 | 2014-01-01 11:05:00
     2 |  16  |     3  | 2014-01-01 11:00:00
     2 |  17  |     3  | 2014-01-01 12:00:00
     1 |  4   |        | 2014-01-01 00:10:00

누군가가 depth칼럼이 나온다는 것을 설명 할 수 있습니까 ? 초기 테이블 구조에는 표시되지 않습니다.
sorin

@sorin, 이것이 실제 오래된 게시물이라는 것을 알고 있지만 Google 에서이 게시물을 우연히 발견하여 귀하의 질문에 대답 할 것이라고 생각했습니다. 깊이는 첫 번째 쿼리에서 리터럴 '1'의 별칭에서 비롯됩니다.
Sam

답변:


11

루트에서 리프까지의 경로를 나타내는 배열은 원하는 정렬 순서를 달성해야합니다.

WITH RECURSIVE node_rec AS (
   (SELECT 1 AS depth, ARRAY[node] AS path, *
    FROM   nodes
    WHERE  parent IS NULL
    LIMIT  10
   )    
    UNION ALL
    SELECT r.depth + 1, r.path || n.node, n.*
    FROM   node_rec r 
    JOIN   nodes    n ON n.parent = r.node
    WHERE  r.depth < 4
)
SELECT *
FROM   node_rec
ORDER  BY path;

두 개 이상의 자식 노드에 동일한 부모 노드가 있으면 타임 스탬프별로 정렬하고 싶습니다.

루트를 향해 경로를 하나씩 이동하고 해당 열을 순서대로 추가하십시오.

WITH RECURSIVE node_rec AS (
   (SELECT 1 AS depth, ARRAY[node] AS path, *
    FROM   nodes
    WHERE  parent IS NULL
    LIMIT  10
   )    
    UNION ALL
    SELECT r.depth + 1, r.path || n.parent, n.*
    FROM   node_rec r 
    JOIN   nodes    n ON n.parent = r.node
    WHERE  r.depth < 4
)
SELECT *
FROM   node_rec
ORDER  BY path, ts;

고마워요, 잘 작동합니다! 그러나 "두 개 이상의 자식 노드에 동일한 부모 노드가있는 경우 타임 스탬프별로 정렬하고 싶습니다"부분은 어떻습니까? 이 접근 방식으로 가능합니까? 항상 더 높은 노드 ID가 나중에 해당되는 것은 아닙니다.
JohnCand

@JohnCand : 루트 방향으로 경로를 하나씩 이동하고 (첫 번째 위치에서 루트 노드를 반복합니다!) 해당 열을 기준으로 추가로 주문할 수 있습니다.
Erwin Brandstetter
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.