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