0

回复 ID 的预期顺序:55, 57, 58, 59, 60, 56 -- 这样整个 1st parent 回复及其所有子项出现在 2nd parent 回复之前 以下 SQL 查询返回错误的结果顺序

WITH RECURSIVE t(replyid, replypid, depth, path, reply, replied, reply_userid) AS (
    (SELECT replyid, replypid, 0, array[replyid], reply, replied, replies.userid, u.displayname, u.email_address,
        (SELECT COUNT(*) FROM reply_revs WHERE replyid = replies.replyid) AS reply_revs
        FROM replies
        LEFT OUTER JOIN users u ON (replies.userid = u.userid)
        WHERE replypid is NULL AND postid = 31 ORDER BY replied)
    UNION ALL
    (SELECT r.replyid, r.replypid, t.depth+1, t.path || r.replypid, r.reply, r.replied, r.userid, u.displayname, u.email_address,
        (SELECT COUNT(*) FROM reply_revs WHERE replyid = r.replyid)
        FROM replies r
        JOIN t ON (r.replypid = t.replyid)
        LEFT OUTER JOIN users u ON (r.userid = u.userid)
        ORDER BY replied)
) SELECT * FROM t

replyid     replypid    depth   path            reply                               replied 
55      NULL        0       {55}        1st parent reply                    2011-02-13 11:40:48.072148-05
56      NULL        0       {56}        2nd parent reply                    2011-02-13 11:41:00.610033-05
57      55          1       {55,55}     1st child to 1st parent reply           2011-02-13 11:41:26.541024-05
58      55          1       {55,55}     2nd child to 1st parent reply           2011-02-13 11:41:39.485405-05
59      55          1       {55,55}     3rd child to 1st parent reply           2011-02-13 11:41:51.35482-05
60      59          2       {55,55,59}  1st child to 3rd child of 1st parent reply  2011-02-13 11:42:14.866852-05

但是,仅将“ ORDER BY path”添加到末尾即可解决此问题,但仅适用于升序

WITH RECURSIVE t(replyid, replypid, depth, path, reply, replied, reply_userid) AS (
    (SELECT replyid, replypid, 0, array[replyid], reply, replied, replies.userid, u.displayname, u.email_address,
        (SELECT COUNT(*) FROM reply_revs WHERE replyid = replies.replyid) AS reply_revs
        FROM replies
        LEFT OUTER JOIN users u ON (replies.userid = u.userid)
        WHERE replypid is NULL AND postid = 31 ORDER BY replied)
    UNION ALL
    (SELECT r.replyid, r.replypid, t.depth+1, t.path || r.replypid, r.reply, r.replied, r.userid, u.displayname, u.email_address,
        (SELECT COUNT(*) FROM reply_revs WHERE replyid = r.replyid)
        FROM replies r
        JOIN t ON (r.replypid = t.replyid)
        LEFT OUTER JOIN users u ON (r.userid = u.userid)
        ORDER BY replied)
) SELECT * FROM t ORDER BY path

replyid replypid    depth   path            reply                               replied 
55      NULL    0       {55}        1st parent reply                    2011-02-13 11:40:48.072148-05
57      55      1       {55,55}     1st child to 1st parent reply           2011-02-13 11:41:26.541024-05
58      55      1       {55,55}     2nd child to 1st parent reply           2011-02-13 11:41:39.485405-05
59      55      1       {55,55}     3rd child to 1st parent reply           2011-02-13 11:41:51.35482-05
60      59      2       {55,55,59}  1st child to 3rd child of 1st parent reply  2011-02-13 11:42:14.866852-05
56      NULL    0       {56}        2nd parent reply                    2011-02-13 11:41:00.610033-05

因此,让我们现在尝试 DESCENDING,而不是附加“ ORDER BY path DESC” 结果是:

replyid replypid    depth   path            reply                               replied 
56      NULL    0       {56}        2nd parent reply                    2011-02-13 11:41:00.610033-05
60      59      2       {55,55,59}  1st child to 3rd child of 1st parent reply  2011-02-13 11:42:14.866852-05
57      55      1       {55,55}     1st child to 1st parent reply           2011-02-13 11:41:26.541024-05
58      55      1       {55,55}     2nd child to 1st parent reply           2011-02-13 11:41:39.485405-05
59      55      1       {55,55}     3rd child to 1st parent reply           2011-02-13 11:41:51.35482-05
55      NULL    0       {55}        1st parent reply                    2011-02-13 11:40:48.072148-05

现在看起来好像第一个父母回复的孩子是第二个父母回复的孩子。

我的问题是:如何对结果进行排序,以便深度 > 0 的子项或结果始终出现在其相应的父项之后而不是其他父项之后?

我想看到的结果:

replyid replypid    depth   path            reply                               replied 
56      NULL    0       {56}        2nd parent reply                    2011-02-13 11:41:00.610033-05
55      NULL    0       {55}        1st parent reply                    2011-02-13 11:40:48.072148-05
57      55      1       {55,55}     1st child to 1st parent reply           2011-02-13 11:41:26.541024-05
58      55      1       {55,55}     2nd child to 1st parent reply           2011-02-13 11:41:39.485405-05
59      55      1       {55,55}     3rd child to 1st parent reply           2011-02-13 11:41:51.35482-05
60      59      2       {55,55,59}  1st child to 3rd child of 1st parent reply  2011-02-13 11:42:14.866852-05

感谢 Freenode 上#postgresql 中的 RhodiumToad,我能够提出以下 PHP 和 SQL 查询,效果非常好!

if (isset($_SESSION["userid"])) {
    $s_col1 = ", (SELECT COUNT(*) FROM votes WHERE replyid = replies.replyid AND userid = %d) AS reply_voted";
    $s_col2 = ", (SELECT COUNT(*) FROM votes WHERE replyid = r.replyid AND userid = %d)";
} else { $s_col1 = ""; $s_col2 = ""; }

if ($sort == "newest") { $s_arr1 = "-extract(epoch from replied)::integer"; $s_arr2 = " || -extract(epoch from r.replied)::integer"; }
else if ($sort == "oldest") { $s_arr1 = "extract(epoch from replied)::integer"; $s_arr2 = " || extract(epoch from r.replied)::integer"; }
else if ($sort == "topvotes") { $s_arr1 = "-votes"; $s_arr2 = " || -r.votes"; }
else { $s_arr1 = ""; $s_arr2 = ""; }

$sql = "WITH RECURSIVE t(replyid, replypid, depth, path, reply, replied, reply_userid) AS (
        (SELECT replyid, replypid, 0, array[$s_arr1,replyid], reply, replied, replies.userid, u.displayname, u.email_address,
            (SELECT COUNT(*) FROM reply_revs WHERE replyid = replies.replyid) AS reply_revs,
            (SELECT COUNT(*) FROM votes WHERE replyid = replies.replyid) AS reply_votes
            $s_col1
        FROM replies
        LEFT OUTER JOIN users u ON (replies.userid = u.userid)
        WHERE replypid is NULL AND postid = %d)
        UNION ALL
        (SELECT r.replyid, r.replypid, t.depth+1, t.path$s_arr2 || r.replyid, r.reply, r.replied, r.userid, u.displayname, u.email_address,
            (SELECT COUNT(*) FROM reply_revs WHERE replyid = r.replyid) AS reply_revs,
            (SELECT COUNT(*) FROM votes WHERE replyid = r.replyid) AS reply_votes
            $s_col2
        FROM replies r
        JOIN t ON (r.replypid = t.replyid)
        LEFT OUTER JOIN users u ON (r.userid = u.userid))
    ) SELECT * FROM t ORDER BY path";
4

2 回答 2

1

在最后一个查询中,您确实有两种类型。父母可以升序或降序排序,但孩子只能升序排序。

在看了这个之后,我相信你可以得到这样的解决方案。

   order by case 
        when depth = 0
            then path
    /*
      secret function that always returns the
      right numbers regardless of whether or not the sort is ascending.
    */
        else XXX_function('DESC', path)
    end desc;

我相信逻辑是合理的,但你必须弄清楚如何替换降序排列的数字,因为事情会“颠倒”。(也许颠倒数组位置)

于 2011-02-14T23:02:18.437 回答
0

是什么让孩子成为第一个孩子?如果是回复日期,您也必须按此值排序。

于 2011-02-14T19:36:58.553 回答