2

I have a sql table which include conversation between users. I need to retrieve the last message from every conversation in order to preview it.

id | sender   | receiver     | message      | date
 1 |        1 |            2 | Hello        | 2015-12-08 20:00
 2 |        2 |            1 | Hey          | 2015-12-08 20:10
 3 |        2 |            1 | You there?   | 2015-12-08 21:00
 4 |        1 |            3 | Yes          | 2015-12-08 21:15
 5 |        4 |            1 | Hey buddy    | 2015-12-08 22:00

I know many similar question on site but i couldn't fix this.

I tried this code but not working properly:

SELECT *
FROM   messages
WHERE  receiver = '{$id}'
GROUP BY sender
ORDER BY id DESC
LIMIT 10;
Fuzzy
  • 3,810
  • 2
  • 15
  • 33
Can1
  • 89
  • 1
  • 13
  • I tried this code but not working properly. `SELECT * FROM messages WHERE receiver = '{$id}' GROUP BY sender ORDER BY id DESC LIMIT 10` – Can1 Jun 29 '16 at 22:17
  • 1
    A receiver's id doesn't constitute a conversation, rather sender's and receiver's id, together, makes a conversation unique. For example, see the first and second row of your table. – Rajdeep Paul Jun 29 '16 at 22:26
  • I believe the issue you have is the the user can be both the sender and receiver in one conversation. Just selecting based on the receiver means you are missing half of your conversation. – ThrowBackDewd Jun 29 '16 at 22:34
  • 1
    But how is it different from the others? – Strawberry Jun 29 '16 at 22:42

4 Answers4

4

Just to define what is a conversation in your table is a pain, i suppose a conversation is all the rows where

(sender=@senderId && receiver=@receiverId) || (sender=@receiverId && receiver=@senderId)

Group by this concept, i don't even want to think it

For me you are missing a concept, the "conversation"

If you have a table conversation like this

ConversationId |  Users1  |  User2

And Message like

Id | ConversationId | UserSendingId | Message | Date

Now you can Group by ConversationId and take the last message like

SELECT *  <-- avoid * better use all row names
FROM Message 
Where id in (
 select max(id) from message group by ConversationId
)

The representation of the conversation table is just a fast approach you can do a better solution with a relation from 1 to many of conversation and users in conversation to avoid modified conversation table when you want to have more than 2 users per conversation.

RJardines
  • 850
  • 9
  • 18
  • 2
    I think the op's model is just fine – Strawberry Jun 29 '16 at 23:02
  • Thank you for your answer @deumber I added conversation coloumn. `SELECT * FROM messages WHERE id IN (SELECT MAX(id) FROM messages GROUP BY conversation) ORDER BY id DESC LIMIT 10` – Can1 Jun 29 '16 at 23:04
3

I think if you want to identify a conversation for a particular user, you will need to select rows where they are either the sender or the receiver.

Then to get the most recent message from the conversation, you can group by whichever one of sender/receiver the current user is not, then select the maximum ID.

SELECT * FROM messages
WHERE id IN (
    SELECT MAX(id) AS last_msg_id 
    FROM messages WHERE receiver = ? OR sender = ? 
    GROUP BY IF(sender = ?, receiver, sender)
)

I don't think this query will perform very well, though. I agree with the other answer that it would be easier to query for conversations if conversations were defined in your database.

Don't Panic
  • 41,125
  • 10
  • 61
  • 80
2

E.g.:

SELECT x.* 
  FROM my_table x
  JOIN 
     ( SELECT LEAST(sender,receiver) user1
            , GREATEST(sender,receiver) user2
            , MAX(date) date 
         FROM my_table 
        GROUP 
           BY user1
            , user2
     ) y
    ON LEAST(sender,receiver) = user1
   AND GREATEST(sender,receiver) = user2
   AND y.date = x.date;
Strawberry
  • 33,750
  • 13
  • 40
  • 57
0
SELECT m.id, m.added_date, m.message, u.username, u.image, m.from_id, m.to_id
FROM tbp_registration AS u 
LEFT JOIN tbp_chats AS m ON m.from_id = u.id 
WHERE m.id IN ( 
  SELECT MAX(id) 
  FROM tbp_chats 
  WHERE from_id = '$user_id' OR to_id = '$user_id' 
  GROUP BY LEAST(from_id, to_id), GREATEST(from_id, to_id)
)
hex494D49
  • 9,109
  • 3
  • 38
  • 47