现在我已经回答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;
我该如何解决这个问题?
答案 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;
这里有很多内容:
表格已加入,并根据JOIN
和WHERE
条款选择了行。
运行窗口函数first_value()
的两个实例(在同一窗口定义上),以从最新帖子中检索username
和updated_at
每个线程。这导致与线程中的帖子一样多的相同的行。
在窗口函数之后执行DISTINCT
步骤,并将每个集合缩减为单个实例。
ORDER BY
,updated_at
引用了 OUT
列(SELECT
列表),而不是其中之一< em> IN
列(FROM
列表)同名。
另一个变体,一个带窗函数{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;