2016-09-12 3 views
1

Я пытаюсь получить список разговоров из базы данных, и мне бы хотелось, чтобы вместе с ними было отображено самое последнее сообщение. У меня возникли проблемы с поиском запроса, который позволяет мне это делать (а это не N + 1).Выберите неагрегатный столбец в группе, на основе соответствующего столбца агрегата

У меня есть эти таблицы:

chats(id, user_id, post_id, created_at) 
messages(id, user_id, chat_id, body, created_at) 

У меня был запрос, как это в виду:

select chats.id, chats.user_id, m.latest from chats 
inner join (
    select chat_id, max(created_at) as latest from messages 
    group by chat_id 
) as m on m.chat_id = chats.id; 

Но я хочу, чтобы добавить тело сообщения из строки, соответствующей max(created_at) результата. Возможно ли получить соответствующий столбец?

ответ

3

Со стандартным SQL это можно сделать с помощью функций окна (см ответ Саги 'ы).

С Postgres, патентованный distinct on() часто быстрее, чем эквивалентное решение с использованием функции окна:

select chats.id, chats.user_id, m.body, m.latest 
from chats 
    join (
    select distinct on (chat_id) chat_id, body, created_at as latest 
    from messages 
    order by chat_id, created_at desc; 
) as m on m.chat_id = chats.id; 

Решение с помощью функции окна является более гибким, хотя. Вы также можете получить последние два (или три или ...) сообщения, тогда как distinct on() вы получите только один.

+0

Это идеальное решение для моего использования, спасибо –

2

Попробуйте использовать ROW_NUMBER():

select chats.id, chats.user_id, m.body from chats 
inner join (
    select chat_id,body , 
      row_number() OVER(PARTITION BY chat_id ORDER BY created_at DESC) as rnk 
    from messages 
) m on m.chat_id = chats.id and m.rnk = 1; 
+0

Интересно, я не знал о функциях окна –

Смежные вопросы