... the latest message in a conversation between two users.
Assuming the users with ID 1
and 3
, like you did in the fiddle, we are interested in the message with the latest created_at
and (sender_id, receiver_id)
being (1,3)
or (3,1)
.
You can use ad-hoc row types to make the syntax short:
SELECT *
FROM messages
WHERE (sender_id, receiver_id) IN ((1,3), (3,1))
ORDER BY created_at DESC
LIMIT 1;
Or explicitly (and slightly faster, also easier to use with indexes):
SELECT *
FROM messages
WHERE (sender_id = 1 AND receiver_id = 3 OR
sender_id = 3 AND receiver_id = 1)
ORDER BY created_at DESC
LIMIT 1;
For all conversations of a user
Added solution as per request in comment.
SELECT DISTINCT ON (user_id) *
FROM (
SELECT 'out' AS type, id, receiver_id AS user_id, body, created_at
FROM messages
WHERE sender_id = 1
UNION ALL
SELECT 'in' AS type, id, sender_id AS user_id, body, created_at
FROM messages
WHERE receiver_id = 1
) sub
ORDER BY user_id, created_at DESC;
The approach here is to fold foreign sender / receiver into one column to simplify the extraction of the last row.
Detailed explanation for DISTINCT ON
in this related answer:
sqlfiddle - with improved and simplified test case