2

我建立了一個論壇,非常喜歡reddit的/ Slashdot的,即遞推式CTE Postgres的:排序/按熱門程度排序的孩子,同時保留樹結構(父母總是以上的兒童)

  • 回覆無限嵌套層次
  • 熱門評論(由喜歡/票訂購)將上升到頂部(自己的嵌套/深度級別內),但樹結構需要保留(父母總是顯示直接以上的兒童)

這裏的樣本表& da TA:

DROP TABLE IF EXISTS "comments"; 
CREATE TABLE comments (
    id BIGINT PRIMARY KEY, 
    parent_id BIGINT, 
    body TEXT NOT NULL, 
    like_score BIGINT, 
    depth BIGINT 
); 

INSERT INTO comments VALUES ( 0, NULL, 'Main top of thread post', 5 , 0); 

INSERT INTO comments VALUES ( 1, 0, 'comment A', 5 , 1); 
INSERT INTO comments VALUES ( 2, 1, 'comment A.A', 3, 2); 
INSERT INTO comments VALUES ( 3, 1, 'comment A.B', 1, 2); 
INSERT INTO comments VALUES ( 9, 3, 'comment A.B.A', 10, 3); 
INSERT INTO comments VALUES (10, 3, 'comment A.B.B', 5, 3); 
INSERT INTO comments VALUES (11, 3, 'comment A.B.C', 8, 3); 
INSERT INTO comments VALUES ( 4, 1, 'comment A.C', 5, 2); 

INSERT INTO comments VALUES (5, 0, 'comment B', 10, 1); 
INSERT INTO comments VALUES (6, 5, 'comment B.A', 7, 2); 
INSERT INTO comments VALUES (7, 5, 'comment B.B', 5, 2); 
INSERT INTO comments VALUES (8, 5, 'comment B.C', 2, 2); 

這裏的遞歸查詢我來了這麼遠,但我無法弄清楚如何訂購的孩子,但保留樹結構(父母應始終以上的兒童)...

WITH RECURSIVE tree AS (
    SELECT 
    ARRAY[]::BIGINT[] AS sortable, 
    id, 
    body, 
    like_score, 
    depth 
    FROM "comments" 
    WHERE parent_id IS NULL 

    UNION ALL 

    SELECT 
    tree.sortable || "comments".like_score || "comments".id, 
    "comments".id, 
    "comments".body, 
    "comments".like_score, 
    "comments".depth 
    FROM "comments", tree 
    WHERE "comments".parent_id = tree.id 
) 
SELECT * FROM tree 
ORDER BY sortable DESC 

此輸出......

+----------------------------------------------------------+ 
|sortable  |id|body     |like_score|depth| 
+----------------------------------------------------------+ 
|{10,5,7,6} |6 |comment B.A   |7   |2 | 
|{10,5,5,7} |7 |comment B.B   |5   |2 | 
|{10,5,2,8} |8 |comment B.C   |2   |2 | 
|{10,5}  |5 |comment B    |10  |1 | 
|{5,1,5,4}  |4 |comment A.C   |5   |2 | 
|{5,1,3,2}  |2 |comment A.A   |3   |2 | 
|{5,1,1,3,10,9}|9 |comment A.B.A   |10  |3 | 
|{5,1,1,3,8,11}|11|comment A.B.C   |8   |3 | 
|{5,1,1,3,5,10}|10|comment A.B.B   |5   |3 | 
|{5,1,1,3}  |3 |comment A.B   |1   |2 | 
|{5,1}   |1 |comment A    |5   |1 | 
|    |0 |Main top of thread post|5   |0 | 
+----------------------------------------------------------+ 

...不過,請注意「的評論B」,「的評論」和「主題發表的主要頂部」是孩子在下面?我如何保持上下文順序?即我想要的輸出是:

+----------------------------------------------------------+ 
|sortable  |id|body     |like_score|depth| 
+----------------------------------------------------------+ 
|    |0 |Main top of thread post|5   |0 | 
|{10,5}  |5 |comment B    |10  |1 | 
|{10,5,7,6} |6 |comment B.A   |7   |2 | 
|{10,5,5,7} |7 |comment B.B   |5   |2 | 
|{10,5,2,8} |8 |comment B.C   |2   |2 | 
|{5,1}   |1 |comment A    |5   |1 | 
|{5,1,5,4}  |4 |comment A.C   |5   |2 | 
|{5,1,3,2}  |2 |comment A.A   |3   |2 | 
|{5,1,1,3}  |3 |comment A.B   |1   |2 | 
|{5,1,1,3,10,9}|9 |comment A.B.A   |10  |3 | 
|{5,1,1,3,8,11}|11|comment A.B.C   |8   |3 | 
|{5,1,1,3,5,10}|10|comment A.B.B   |5   |3 | 
+----------------------------------------------------------+ 

其實我希望用戶能夠通過多種方法進行排序:

  • 最受歡迎的第一
  • 最流行的第一
  • 新的排在前面
  • 從舊到新

...但在任何情況下,父母都需要被展現在他們的孩子之上。但我只是在這裏使用「like_score」作爲例子,我應該能夠從那裏找出其餘的。

花了很多時間研究網絡和嘗試自己,感覺就像我越來越接近,但無法弄清楚這最後一部分。

回答

1

1.

tree.sortable || -"comments".like_score || "comments".id 
       ^
       /|\ 
        | 
        | 

2.

ORDER BY sortable 

WITH RECURSIVE tree AS (
    SELECT 
    ARRAY[]::BIGINT[] AS sortable, 
    id, 
    body, 
    like_score, 
    depth 
    FROM "comments" 
    WHERE parent_id IS NULL 

    UNION ALL 

    SELECT 
    tree.sortable || -"comments".like_score || "comments".id, 
    "comments".id, 
    "comments".body, 
    "comments".like_score, 
    "comments".depth 
    FROM "comments", tree 
    WHERE "comments".parent_id = tree.id 
) 
SELECT * FROM tree 
ORDER BY sortable 

+-------------------+----+-------------------------+------------+-------+ 
| sortable   | id | body     | like_score | depth | 
+-------------------+----+-------------------------+------------+-------+ 
| (null)   | 0 | Main top of thread post | 5   | 0  | 
+-------------------+----+-------------------------+------------+-------+ 
| {-10,5}   | 5 | comment B    | 10   | 1  | 
+-------------------+----+-------------------------+------------+-------+ 
| {-10,5,-7,6}  | 6 | comment B.A    | 7   | 2  | 
+-------------------+----+-------------------------+------------+-------+ 
| {-10,5,-5,7}  | 7 | comment B.B    | 5   | 2  | 
+-------------------+----+-------------------------+------------+-------+ 
| {-10,5,-2,8}  | 8 | comment B.C    | 2   | 2  | 
+-------------------+----+-------------------------+------------+-------+ 
| {-5,1}   | 1 | comment A    | 5   | 1  | 
+-------------------+----+-------------------------+------------+-------+ 
| {-5,1,-5,4}  | 4 | comment A.C    | 5   | 2  | 
+-------------------+----+-------------------------+------------+-------+ 
| {-5,1,-3,2}  | 2 | comment A.A    | 3   | 2  | 
+-------------------+----+-------------------------+------------+-------+ 
| {-5,1,-1,3}  | 3 | comment A.B    | 1   | 2  | 
+-------------------+----+-------------------------+------------+-------+ 
| {-5,1,-1,3,-10,9} | 9 | comment A.B.A   | 10   | 3  | 
+-------------------+----+-------------------------+------------+-------+ 
| {-5,1,-1,3,-8,11} | 11 | comment A.B.C   | 8   | 3  | 
+-------------------+----+-------------------------+------------+-------+ 
| {-5,1,-1,3,-5,10} | 10 | comment A.B.B   | 5   | 3  | 
+-------------------+----+-------------------------+------------+-------+ 
+0

太棒了,謝謝!我早些時候嘗試了一些'0場'的東西,但在錯誤的ASC/DESC命令錯誤的地方...太近了,但是很遠,哈哈!所以我想'|| 「評論」.id'現在是多餘的,我可以刪除它?非常感謝您對這些差異的明確解釋,並且包含示例輸出,使其非常易於理解。 – YeB

+1

不客氣:-)我不會刪除'ID',因爲它是一個平等的'like_score'在同一級別的情況下破產 –

+0

哦,是的,你是對的,不知道爲什麼我認爲我沒有'不再需要它了。你是怎麼產生你的ASCII輸出表的?您是否在使用可爲您生成它的SQL GUI? – YeB

0

選中此:

WITH RECURSIVE tree AS (
    SELECT 
    ARRAY[]::BIGINT[] AS sortable, 
    id, 
    body, 
    like_score, 
    depth, 
    lpad(id::text, 2, '0') as path 
    FROM "comments" 
    WHERE parent_id IS NULL 

    UNION ALL 

    SELECT 
    tree.sortable || "comments".like_score || "comments".id, 
    "comments".id, 
    "comments".body, 
    "comments".like_score, 
    "comments".depth, 
    tree.path || '/' || lpad("comments".id::text, 2, '0') as path 
    FROM "comments", tree 
    WHERE "comments".parent_id = tree.id 
) 
SELECT * FROM tree 
ORDER BY path 

請注意,你可以用你想要的數字的任何數字替換參數2lpad

+0

根據請求的結果驗證您的結果 –

+0

@DuduMarkovitz您說得對。你的回答是正確的。 – wind39