Mysql привести 2 столбца к единому идентификатору

280
04 марта 2017, 03:31

Есть таблица сообщений вида:

|id|sender_id|recipient_id|     date_sent     |
_______________________________________________
|1 |    100  |     101    |2017-03-02 08:03:45|
-----------------------------------------------
|2 |    100  |     101    |2017-03-02 08:10:45|
-----------------------------------------------
|3 |    101  |     100    |2017-03-02 09:55:01|

И так далее. Для расшифровки:

  1. ID сообщения
  2. ID отправителя сообщения
  3. ID получателя сообщения
  4. Дата отправки сообщения Есть еще поля типа самого сообщения, но в вопросе оно никчему.

Нужно:

Вывести диалоги для конкретного юзера с каждым другим юзером, с которым он общался. (сообщения вконтакте для примера). Т.е. мне нужно оставить по последнему сообщению с каждым юзером. Причем, если (как я пытался) повесить group by на sender_id, то в случае исходящего сообщения все ок, а если сообщения входящие (без ответа), они минуют group by. Все это пробовал и через MAX по даному совету. В теории вроде понятно, но на практике все уходит в пропасть. У меня 2 идентификатора и как их превратить в единый (чтобы запрос понимал, что 100 и 101, и 101 и 100 это один диалог. Буду очень благодарен за любую помощь.

Answer 1

Попробуйте такое вот:

SELECT *
FROM dialogs 
WHERE (LEAST(sender_id, recipient_id), GREATEST(sender_id, recipient_id), date_sent) IN
    (
    SELECT LEAST(sender_id, recipient_id), GREATEST(sender_id, recipient_id), MAX(date_sent)
    FROM dialogs 
    WHERE @user IN (sender_id, recipient_id)
    GROUP BY LEAST(sender_id, recipient_id), GREATEST(sender_id, recipient_id)
    )
Answer 2

Попробуйте такой подход (мне сейчас, к сожалению, не на чем проверить):

SELECT all_dialogs.sender_id, all_dialogs.recipient_id, MAX(all_dialogs.date_sent)
FROM 
(
  SELECT sender_id, recipient_id, date_sent
  FROM dialogs 
  WHERE sender_id = @user_id 
  GROUP BY  sender_id, recipient_id
  UNION ALL 
  SELECT recipient_id, sender_id, date_sent
  FROM dialogs 
  WHERE recipient_id  = @user_id 
  GROUP BY sender_id, recipient_id 
) all_dialogs
GROUP BY all_dialogs.sender_id, all_dialogs.recipient_id
Answer 3

чтобы запрос понимал, что 100 и 101, и 101 и 100 это один диалог

Ваша текущая структура данных крайне неудобна для этих целей.
Как бонус - она создаёт непреодолимые препятствия при попытке организовать групповой чат.

Предлагаю другую структуру:

Conversation (id, created, created_by)
Participants (conversation_id, user_id)
Messages (id, conversation_id, user_id(или participant_id), date_sent, content)

Т.е. появляются сущности самих диалогов, участников диалогов, и собственно сообщений.

Тогда ваша задача будет решаться например так:

SELECT m.id FROM Conversation c
JOIN Participants p ON c.id = p.conversation_id
JOIN Messages m ON m.conv_id = c.id
WHERE p.user_id = :user_id
GROUP BY c.id
HAVING m.date_sent = MAX(m.date_sent)
ORDER BY m.date_sent DESC

На реальной структуре данных, можно будет размышлять об оптимизации.

READ ALSO
Ввод данных в таблицу

Ввод данных в таблицу

Имеются 3 таблицы:

269
Есть ли замена WebEngine?

Есть ли замена WebEngine?

Есть ли какая нибудь замена WebEngine? Потому что в моем приложении есть подозрение, что он является причиной утечки оперативки и хотелось бы заменить...

224
Spring MVC pagination

Spring MVC pagination

Прикрутил к простому CRUD приложению пейджинг следующим образом:

493