Получение строки с максимальным значением для столбца из союза - PullRequest
2 голосов
/ 06 ноября 2011

Таблицы

форумы

  • forum_id
  • имя

тем

  • thread_id
  • forum_id
  • user_id
  • добавлено_ts

thread_replies

  • thread_reply_id
  • thread_id
  • user_id
  • добавлено_10

пользователи

  • user_id
  • имя пользователя

Проблема

Я хочу вернуть список форумов с самым последним сообщением для каждого.Эффективно.Отчасти проблема в том, что сообщения распределяются между потоками и thread_replies.

Мой первый инстинкт - получить UNION потоков и thread_replies с нужными мне данными:

SELECT * FROM ((SELECT forum_id, thread_id, user_id, added_ts FROM threads t)
UNION (SELECT t1.forum_id, r.thread_id, r.user_id, r.added_ts FROM thread_replies r 
      INNER JOIN threads t1 ON t1.thread_id = r.thread_id)) messages;

Now I 'у нас есть список всех сообщений с forum_id, thread_id, user_id и Added_ts.Следующим моим инстинктом было присоединение к этой таблице в таблице форумов, но я не вижу четкого способа свести это значение к последнему значению add_ts для каждого форума, в то же время возвращая оставшиеся необходимые данные.

SELECT * FROM forums f 
INNER JOIN 
  (SELECT messages.*, users.username FROM
     ((SELECT forum_id, thread_id, user_id, added_ts FROM threads t) 
       UNION 
      (SELECT t1.forum_id, r.thread_id, r.user_id, r.added_ts 
       FROM thread_replies r 
       INNER JOIN threads t1 ON t1.thread_id = r.thread_id)) messages 
       INNER JOIN users ON messages.user_id = users.user_id 
       ORDER BY messages.added_ts) last_replies ON last_replies.forum_id = f.forum_id;

Я пробовал GROUP BY forum_id в сочетании с MAX (last_replies.added_ts), но это только два поля результирующего набора, которые я могу выбрать, используя функции group by и агрегатные функции, насколько я могу судить.

SELECT f.forum_id, MAX(last_replies.added_ts)
FROM forums f
INNER JOIN (
   SELECT messages.*, users.username
   FROM (
      (SELECT forum_id, thread_id, user_id, added_ts
       FROM threads t)
      UNION
      (SELECT t1.forum_id, r.thread_id, r.user_id, r.added_ts
       FROM thread_replies r
       INNER JOIN threads t1 ON t1.thread_id = r.thread_id)) messages
       INNER JOIN users ON messages.user_id = users.user_id
      ORDER BY messages.added_ts
        ) last_replies ON last_replies.forum_id = f.forum_id GROUP BY f.forum_id;

Я думаю, что мог бы быть способ сделать это, используя ORDER BY add_ts DESC и LIMIT 1, но я также не могу понять, как заставить это работать.Я надеюсь получить здесь несколько хороших идей, которые могут направить меня в правильном направлении.

Решение

Основываясь на выбранном ниже решении, я сформулировал этот запрос:

SELECT f.*, last_replies.*, u.username 
FROM forums f 
INNER JOIN (
    SELECT DISTINCT ON (messages.forum_id) messages.*
    FROM (
        (SELECT forum_id, thread_id, user_id, added_ts FROM threads t)
    UNION
        (SELECT t1.forum_id, r.thread_id, r.user_id, r.added_ts FROM thread_replies r INNER JOIN threads t1 ON t1.thread_id = r.thread_id)
    ) messages
   ORDER BY messages.forum_id, messages.added_ts DESC
) last_replies ON last_replies.forum_id = f.forum_id
INNER JOIN users u ON last_replies.user_id = u.user_id;

1 Ответ

2 голосов
/ 06 ноября 2011

Использовать DISTINCT ON ... ЗАКАЗАТЬ ПО:

http://www.postgresql.org/docs/current/static/sql-select.html#SQL-DISTINCT

...