Reputation: 3
I have a messages table with columns like
message_id, message_to_id, message_from_id, message_body, project_id.
I want a list of message threads for a particular user. Message thread should have a unique combination of fields message_to_id, message_from_id and project_id.
Earlier I was using group by on project_id but I don't want to make them group message over project.
SELECT * FROM message
WHERE message_to = '{$user_id}' OR message_from = '{$user_id}'
GROUP BY project
This didn't work as expected.
SELECT *
FROM message
WHERE message_to = '{$user_id}'
GROUP BY message_from
UNION
SELECT *
FROM message
WHERE message_from = '{$user_id}'
GROUP BY message_to
This is showing me combinations of message_from and message_to which I don't want.
I want a message thread per user combination on a single project.
Sample Data
message_id | message_from_id | message_to_id | project_id | message _body
1 | 283 | 284 | 4 | Hello
2 | 284 | 283 | 4 | Hi
3 | 285 | 283 | 4 | Hey there!
4 | 283 | 285 | 4 | Greetings
5 | 283 | 284 | 6 | Cool!
What I want
message_id | message_from_id | message_to_id | project_id | message _body
1 | 283 | 284 | 4 | Hello
3 | 285 | 283 | 4 | Hey there!
5 | 283 | 284 | 6 | Cool!
i.e ignore message_from_id and message_to_id ordering but together with project_id they should be unique.
Upvotes: 0
Views: 78
Reputation: 1084
I came up with a completely different solutions using an ON
or ranking approach (ROW_NUMBER
or DENSE_RANK
) although this wasn't compatible with all SQL versions, looking around I found a JOIN
approach that appears to do the job.
Here is my result:
SELECT message.message_id, message_to_id, message.message_from_id, message.project_id, message.message_body FROM
message
INNER JOIN
(
SELECT MIN(message_id) message_idMIN FROM message WHERE message_to_id = 283 GROUP BY project_id, message_to_id
UNION
SELECT MIN(message_id) message_idMIN FROM message WHERE message_from_id = 283 GROUP BY project_id, message_from_id
) message_group
ON message.message_id = message_group.message_idMIN;
See the fiddle here: http://sqlfiddle.com/#!9/ef36a1/32
Upvotes: 0
Reputation: 3
The correct answer is to ignore the combination of message_to and message_from and give distinct of the same.
SELECT DISTINCT
CASE WHEN message_from_id < message_to_id
THEN message_from_id
ELSE message_to_id END as message_from_id,
CASE WHEN message_from_id < message_to_id
THEN message_to_id
ELSE message_from_id END as message_to_id,
project
FROM message
WHERE message_to_id = '{$user_id}' OR message_from_id = '{$user_id}'
This way it can work without Group By Clause.
But the problem with this solution is I can't get any non-distinct columns like sent_at (which I didn't mention here).
Upvotes: 0