Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finding latest message from table, grouped by user in mysql

I have a private messages table on my site and for a while now I have had an inbox and sentbox separate. I want to combine the inbox/sentbox only showing the latest message either to or from a specific user.

TLDR: I want to show the latest message grouped by sent to or from each user.

Example of table

|  id | fromuser | fromid | touser | toid | message    |  timestamp            |
--------------------------------------------------------------------------------
|  1  | user1    |  1     | user2  |  2   | Hello..    |  2015-01-01 00:00:00  |
|  2  | user1    |  1     | user3  |  3   | okay...    |  2015-01-02 00:00:00  |
|  3  | user3    |  3     | user1  |  1   | not....    |  2015-01-03 00:00:00  |
|  4  | user2    |  2     | user3  |  3   | New....    |  2015-01-04 00:00:00  |
|  5  | user2    |  2     | user1  |  1   | With.....  |  2015-01-05 00:00:00  |
--------------------------------------------------------------------------------

Result i'm looking for when in user 1

|  id | fromuser | fromid | touser | toid | message    |  timestamp            |
--------------------------------------------------------------------------------
|  3  | user3    |  3     | user1  |  1   | not....    |  2015-01-03 00:00:00  |
|  5  | user2    |  2     | user1  |  1   | With.....  |  2015-01-05 00:00:00  |
--------------------------------------------------------------------------------

Using the code below I can get it to show one message to or from each user but it shows the oldest message not the newest.

mysql_query("SELECT m1.*, users.id AS userid, users.username 
    FROM pm AS m1, pm AS m2, users 
    WHERE ((m1.fromuser='".$_SESSION['userName']."' AND users.id=m1.toid) 
    OR (m1.touser='".$_SESSION['userName']."' AND users.id=m1.fromid)) 
    AND m2.id=m1.id ORDER BY timestamp DESC");
like image 303
David Wright Avatar asked Apr 22 '15 13:04

David Wright


1 Answers

Try this out:

select * from messages m where not exists ( select 1 from messages mm where (mm.fromuser = m.fromuser or mm.fromuser = m.touser) AND (mm.touser = m.touser or mm.touser = m.fromuser) and mm.timestamp > m.timestamp ) and m.fromuser = 'user1' or m.touser = 'user1';

demo here.

It would probably be better, going forward, to flag conversations between two users as a particular conversation, then every message belongs to a conversation, and thus it becomes far easier to find conversations the user is involved in, and info about messages related to the conversation. Anyway.

Try this one instead. Ugh.

select m.* 
  from messages m 
     left join messages m2 
       on ((m.fromuser = m2.fromuser and m.touser = m2.touser) 
           or (m.fromuser = m2.touser and m.touser = m2.fromuser)) 
         and m.timestamp < m2.timestamp 
  where (m.fromuser = 'user1' or m.touser = 'user1') 
  and m2.id is null;

It's likely to be superior to the not exists version, even if i do manage to fix that one.

this fiddle actually works

like image 128
pala_ Avatar answered Sep 25 '22 16:09

pala_