ฉันจะจัดเรียงผลลัพธ์ของข้อความค้นหาแบบเรียกซ้ำในลักษณะคล้ายต้นไม้แบบขยายได้อย่างไร


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

@ โซรินฉันรู้ว่านี่เป็นโพสต์เก่าจริง แต่ฉันเพิ่งเจอมันใน 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.