In PostgreSQL, DISTINCT ON
is probably the optimal solution for this kind of query:
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
This retrieve articles with the latest comment and associated additional columns.
Explanation, links and a benchmark in this closely related answer.
To get the latest 10, wrap this in a subquery:
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;
Alternatively, you could use window functions in combination with standard 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;
This works, because DISTINCT
(unlike aggregate functions) is applied after
window functions.
You'd have to test which is faster. I'd guess the last one is slower.