Grab the correct set of data from database Mysql/MariaDB

MysteryMan :

Consider the following data from a table

SELECT * FROM messages;

+----+------------+------------+----------------------------------------------------------------+------------+
| id | did_from   | did_to     | message                                                        | timestamp  |
+----+------------+------------+----------------------------------------------------------------+------------+
| 28 | 3369377501 | 3365024246 | Hey                                                            | 1585465342 |
| 29 | 3365024246 | 3369377501 | Whatcha doing?                                                 | 1585465349 |
| 30 | 3369377501 | 3365024246 | Driving, whatcha doing?                                        | 1585465369 |
| 31 | 3365024246 | 3369377501 | Driving and texting.                                           | 1585465375 |
| 32 | 3369377501 | 3365024246 | Hmmmm, are you sure you should be doing that?                  | 1585465395 |
| 39 | 3365024246 | 3369377501 | Yes because im a textpert                                      | 1585465500 |
| 40 | 3365024246 | 3369377501 | An expert at texting                                           | 1585465517 |
| 42 | 3365024246 | 3369377501 | Rejecting the notion that you think ill be wrecking            | 1585465550 |
| 43 | 3365024246 | 3369377501 | Due to the fact that im distracted?                            | 1585465559 |
| 44 | 3365024246 | 3369377501 | I multi-task best behind the wheel when i get textually active | 1585465577 |
| 50 | 3365024246 | 3369377501 | texting is cool                                                | 1585518726 |
| 51 | 3369377501 | 3365024246 | I agree                                                        | 1585518740 |
| 52 | 3365024246 | 3369377501 | Hey                                                            | 1585573071 |
| 53 | 3369377501 | 3365024246 | Hey                                                            | 1585573087 |
| 54 | 3365024246 | 3369377501 | whats up                                                       | 1585576304 |
+----+------------+------------+----------------------------------------------------------------+------------+

If this is a conversation between 2 people and I want to get the last message by ethier person in the conversation I run the query

SELECT * FROM messages WHERE (id IN ( SELECT MAX(id) FROM messages GROUP BY did_from ) AND did_to='3365024246') OR (id IN ( SELECT MAX(id) FROM messages GROUP BY did_from ) AND did_from='3365024246') ORDER BY id DESC

Assumptions

DID: 3365024246 is the user who is logged in

We do not know who the other person in the conversations are we are searching and getting a list of conversations and displaying the last message(ether by the person logged in or the other person)

Problem

The current query will return

+----+------------+------------+----------+------------+
| id | did_from   | did_to     | message  | timestamp  |
+----+------------+------------+----------+------------+
| 54 | 3365024246 | 3369377501 | whats up | 1585576304 |
| 53 | 3369377501 | 3365024246 | Hey      | 1585573087 |
+----+------------+------------+----------+------------+

Whats Expected

+----+------------+------------+----------+------------+
| id | did_from   | did_to     | message  | timestamp  |
+----+------------+------------+----------+------------+
| 54 | 365024246 | 3369377501 | whats up | 1585576304 |
+----+------------+------------+----------+------------+
GMB :

If you are running MySQL 8.0, you can do this with window functions:

select *
from (
    select 
        m.*, 
        row_number() over(
            partition by least(did_from, did_to), greatest(did_from, did_to)
            order by timestamp desc
        ) rn
    from messages m
    where 3365024246 in (did_from, did_to)
) t 
where rn = 1

The important thing is to partition by the smallest and greatest peer, which avoids putting messages of the same conversation in the same group, regardless of who sent or received.

In earlier versions, you could use a correlated subquery for filtering:

select m.*
from messages m
where 
    3365024246 in (m1.did_from, m1.did_to) 
    and m.id = (
        select m1.id
        from messages m1
        where               
            and least(m1.did_from, m1.did_to) = least(m.did_from, m.did_to)
            and greatest(m1.did_from, m1.did_to) = greatest(m.did_from, m.did_to)
        order by m1.timestamp desc
        limit 1
    )

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=386127&siteId=1