获取max(时间戳)行

时间:2012-11-13 23:03:11

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

我需要选择最近评论过的文章,每篇文章的最后一条评论,即包含max(c.created)的行的其他列:

SELECT a.id, a.title, a.text, max(c.created) AS cid, c.text?
FROM subscriptions s
JOIN articles a ON a.id=s.article_id
JOIN comments c ON c.article_id=a.id
WHERE s.user_id=%d
GROUP BY a.id, a.title, a.text
ORDER BY max(c.created) DESC LIMIT 10;

Postgres告诉我,我必须将c.text放入GROUP BY。显然,我不想这样做。最小/最大也不合适。我不知道如何选择这个。

请建议。

1 个答案:

答案 0 :(得分:2)

在PostgreSQL中,DISTINCT ON可能是此类查询的最佳解决方案:

SELECT DISTINCT ON (a.id)
       a.id, a.title, a.text, c.created, c.text
FROM   subscriptions s
JOIN   articles      a ON a.id = s.article_id
JOIN   comments      c ON c.article_id = a.id
WHERE  s.user_id = %d
ORDER  BY a.id, c.created DESC

这将检索包含最新评论和相关附加列的文章 此closely related answer中的说明,链接和基准。

要获取最新的10,请将其包装在子查询中:

SELECT *
FROM  (
    SELECT DISTINCT ON (a.id)
             a.id, a.title, a.text, c.created, c.text
    FROM   subscriptions s
    JOIN   articles      a ON a.id = s.article_id
    JOIN   comments      c ON c.article_id = a.id
    WHERE  s.user_id = 12
    ORDER  BY a.id, c.created DESC
    ) x
ORDER  BY created DESC
LIMIT  10;

或者,您可以将window functions与标准 DISTINCT 结合使用:

SELECT DISTINCT
       a.id, a.title, a.text, c.created, c.text
      ,first_value(c.created) OVER w AS c_created
      ,first_value(c.text)    OVER w AS c_text
FROM   subscriptions s
JOIN   articles      a ON a.id = s.article_id
JOIN   comments      c ON c.article_id = a.id
WHERE  s.user_id = 12
WINDOW w AS (PARTITION BY c.article_id ORDER BY c.created DESC)
ORDER  BY c_created DESC
LIMIT  10;

这是有效的,因为DISTINCT(与聚合函数不同)应用了after窗口函数 你必须测试哪个更快。我猜最后一个比较慢。