0

I have a messages table. As a side note all ids are UUIDs not INTs

messages
 - id
 - from_id
 - to_id
 - text
 - inserted_at

I want to retrieve the last message that was either sent or received by user x with every other user.

So given a table with this data

--------------------------------------------------
| id |  from_id  | to_id  |  text   | inserted_at |
--------------------------------------------------- 
| 1 |      1     |    2   |  hello  | 2020-01-01  |
| 2 |      2     |    1   |  sup    | 2020-01-02  |
| 3 |      1     |    3   |  hello  | 2020-01-01  |
| 4 |      2     |    3   |  howdy  | 2020-01-01  |

I want to retrieve the messages for user 1.

Pseudo SQL

SELECT DISTINCT OR (from_id, to_id) text, inserted_at 
FROM messages 
WHERE from_id = 1 OR to_id = 1 
ORDER BY inserted_at;

The result should be:

--------------------------------------------------
| id |  from_id  | to_id  |  text   | inserted_at |
--------------------------------------------------- 
| 2 |      2     |    1   |  sup    | 2020-01-02  |
| 3 |      1     |    3   |  hello  | 2020-01-01  |

2 Answers 2

2

Use LEAST and GREATEST to get the to/from tuples ordered:

SELECT DISTINCT ON (LEAST(from_id, to_id), GREATEST(from_id, to_id))
  from_id, to_id, text, inserted_at
FROM messages 
WHERE from_id = 1 OR to_id = 1 
ORDER BY LEAST(from_id, to_id), GREATEST(from_id, to_id), inserted_at;
Sign up to request clarification or add additional context in comments.

Comments

2

You can order messages for each user by partitioning your data by LEAST(from_id, to_id), GREATEST(from_id, to_id) and ordering by inserted_at, then you can select only the first rows from that set:

WITH CTE AS (
  SELECT *,
         ROW_NUMBER() OVER (PARTITION BY LEAST(from_id, to_id), GREATEST(from_id, to_id) ORDER BY inserted_at DESC) AS rn
  FROM messages
)
SELECT id, from_id, to_id, text, inserted_at
FROM CTE
WHERE (from_id = 1 OR to_id = 1)
  AND rn = 1
ORDER BY id

Output:

id  from_id     to_id   text    inserted_at
2   2           1       sup     2020-01-02T00:00:00.000Z
3   1           3       hello   2020-01-01T00:00:00.000Z

Demo on db-fiddle

2 Comments

what if I'm using UUID for ids?
That should still work as both inputs just need to be the same datatype, and comparable.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.