ORDER BY 来自主查询和子查询的替代值

ORDER BY alternative values from main- and subquery

现在我有一个看起来像这样的查询:

SELECT id 
FROM post_table post
WHERE post.post_user_id = user_id
ORDER BY (SELECT max(comment_created_date) 
          FROM comments_table WHERE comments_post_id = post.id) DESC,
 post.post_created_date DESC

我对这个查询的想法是它会像这样排序一系列帖子

Post 1:
    created Date: Jan 1 2015
    comments : []

Post 2:
     created Date: Jan 5 2015
     comments : []

Post 3:
     created Date : December 1 2014
     comments: [
         0: Created Date: Jan 6 2015
      ]

所以在这种情况下,帖子的返回顺序是

Post3,Post2,Post1

因为Post3的评论比其他任何帖子都新,而Post2是在Post1之前创建的。

但是当我 运行 查询时,帖子仍然全部按创建日期排序,查询似乎没有考虑评论的创建日期。

它应该像这样工作:

SELECT id 
FROM   post_table p
WHERE  post_user_id = $user_id  -- this is your input parameter
ORDER  BY <b>GREATEST(</b>
   (
   SELECT max(comment_created_date) 
   FROM   comments_table
   WHERE  comments_post_id = p.id
   )
 , post_created_date<b>)</b> DESC NULLS LAST;

如果日期列可以为 NULL,您需要添加 NULLS LAST

  • PostgreSQL sort by datetime asc, null first?

如果评论只能晚于帖子(有意义),您可以使用COALESCE instead of GREATEST

更清洁的替代方案(可能更快也可能不会更快,具体取决于数据分布):

SELECT id 
FROM   post_table p
LEFT   JOIN  (
   SELECT comments_post_id AS id, max(comment_created_date) AS max_date
   FROM   comments_table
   GROUP  BY 1
   ) c USING (id)
WHERE  post_user_id = $user_id
ORDER  BY GREATEST(c.max_date, p.post_created_date) DESC NULLS LAST;

因为你有 pg 9.3,你也可以使用 LATERAL 连接。可能更快:

SELECT id 
FROM   post_table p
LEFT   JOIN  LATERAL (
   SELECT max(comment_created_date) AS max_date
   FROM   comments_table
   WHERE  comments_post_id = p.id
   GROUP  BY comments_post_id
   ) c ON TRUE
WHERE  post_user_id = $user_id
ORDER  BY GREATEST(c.max_date, p.post_created_date) DESC NULLS LAST;

如果这是一个命中率很高的查询,我建议的另一件事是在 'date_last_commented' 的 post_table 上创建一个计算列 并使用触发器在评论 table.

的任何插入或更新时更新它

然后您可以运行简单查询:

SELECT id 
FROM post_table post
WHERE post.post_user_id = user_id
ORDER BY post.date_last_commented DESC nulls last, post.post_created_date DESC
;