Получите правильный набор данных из базы данных Mysql / MariaDB - PullRequest
1 голос
/ 30 марта 2020

Рассмотрим следующие данные из таблицы

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 |
+----+------------+------------+----------------------------------------------------------------+------------+

Если это разговор между двумя людьми, и я хочу получить последнее сообщение от другого человека в беседа, на которую я запускаю запрос

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

Допущения

DID: 3365024246 - это пользователь, вошедший в систему

Мы не знаем, кто другой человек в разговорах: мы ищем и получаем список разговоров и показываем последнее сообщение (эфир от лица, вошедшего в систему или от другого человека)

Проблема

Текущий запрос вернется

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

Что ожидается

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

1 Ответ

2 голосов
/ 30 марта 2020

Если вы используете MySQL 8.0, вы можете сделать это с помощью оконных функций:

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

Важно разделить на наименьший и наибольший одноранговый узел, чтобы избежать размещения сообщений одного и того же разговора. в той же группе, независимо от того, кто отправил или получил.

В более ранних версиях для фильтрации можно было использовать коррелированный подзапрос:

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
    )
...