选择所有主题并按最新顺序排序

时间:2014-07-07 20:20:06

标签: sql postgresql greatest-n-per-group window-functions

现在我已经回答Select all forums and get latest post too.. how?个问题,我正在尝试编写一个查询来选择一个特定论坛中的所有主题,并按最新帖子的日期排序(列"的updated_at"。)

这是我的结构:

forums                      forum_threads              forum_posts
----------                  -------------             -----------
id                          id                        id
parent_forum (NULLABLE)     forum_id                  content
name                        user_id                   thread_id
description                 title                     user_id
icon                        views                     updated_at
                            created_at                created_at
                            updated_at
                            last_post_id (NULLABLE)

我尝试编写此查询,但它可以工作..但不是预期的:它不会按照上次发布日期排序:

SELECT DISTINCT ON(t.id) t.id, u.username, p.updated_at, t.title
FROM   forum_threads             t
LEFT   JOIN forum_posts   p ON p.thread_id = t.id
LEFT   JOIN users         u ON u.id = p.user_id
WHERE t.forum_id = 3
ORDER  BY t.id, p.updated_at DESC;

我该如何解决这个问题?

2 个答案:

答案 0 :(得分:2)

假设您希望每个帖子都有单行而不是所有帖子的所有行。

DISTINCT ON 仍然是最方便的工具。但是前导ORDER BY项必须与DISTINCT ON子句的表达式匹配。如果您想以其他方式对结果进行排序,则需要将其包装到子查询中并将另一个ORDER BY添加到外部查询中:

SELECT *
FROM  (
   SELECT DISTINCT ON (t.id)
          t.id, u.username, p.updated_at, t.title
   FROM   forum_threads      t
   LEFT   JOIN forum_posts   p ON p.thread_id = t.id
   LEFT   JOIN users         u ON u.id = p.user_id
   WHERE  t.forum_id = 3
   ORDER  BY t.id, p.updated_at DESC
   ) sub
ORDER  BY updated_at DESC;

如果您因某种未知原因正在寻找没有子查询的查询,那么这也应该有效:

SELECT DISTINCT
       t.id
     , first_value(u.username)   OVER w AS username
     , first_value(p.updated_at) OVER w AS updated_at
     , t.title
FROM   forum_threads      t
LEFT   JOIN forum_posts   p ON p.thread_id = t.id
LEFT   JOIN users         u ON u.id = p.user_id
WHERE  t.forum_id = 3
WINDOW w AS (PARTITION BY t.id ORDER BY p.updated_at DESC)
ORDER  BY updated_at DESC;

这里有很多内容:

  1. 表格已加入,并根据JOINWHERE条款选择了行。

  2. 运行窗口函数first_value()的两个实例(在同一窗口定义上),以从最新帖子中检索usernameupdated_at 每个线程。这导致与线程中的帖子一样多的相同的行。

  3. 在窗口函数之后执行DISTINCT步骤,并将每个集合缩减为单个实例。

  4. 最后应用了
  5. ORDER BYupdated_at引用了 OUT 列(SELECT列表),而不是其中之一< em> IN 列(FROM列表)同名。

  6. 另一个变体,一个带窗函数{strong}的子查询

    row_number()

    类似案例:

    你必须测试哪个更快。取决于几种情况。

答案 1 :(得分:0)

忘记distinct on

SELECT t.id, u.username, p.updated_at, t.title
FROM   forum_threads             t
LEFT   JOIN forum_posts   p ON p.thread_id = t.id
LEFT   JOIN users         u ON u.id = p.user_id
WHERE t.forum_id = 3
ORDER  BY p.updated_at DESC;