#mysql #sql
#mysql #sql
Вопрос:
Я создаю систему обмена сообщениями, ниже приведены мои таблицы.
table --users
|u_id | Name |
| 01 | Aku |
| 02 | Sika |
| 03 | Admin|
table --messages
|m_id | sender_id | Body | sender_deleted | msgTime |
| 100 | 01 | hello | Yes | 16:04 |
| 200 | 02 | Hi | no | 16:08 |
table --recipient
|m_id | recipient_id | status | recipient_deleted |
|100 | 02 | read | no |
|200 | 01 | unread | no |
ПРОБЛЕМА
Я хочу запрашивать диалог из этих таблиц только между двумя сторонами (таким образом u_id=01 and u_id=02
), опять же, я хочу скрыть сообщения для sender_id, когда sender_deleted=yes
но показывать то же сообщение для recipient_id
if recipient_deleted = no
ПРИМЕЧАНИЕ-ОБНОВИТЬ
-
Я хочу, чтобы пользователь с
u_id=01
видел только сообщение сm_id=200
при просмотре на ее странице -
Я хочу, чтобы пользователь с
u_id=02
видел сообщения сm_id=100
иm_id=200
при просмотре на ее странице
Это то, что я пробовал, но я не знаю, как это сделать
SELECT
m.sender_id,
m.Body,
u.Name,
u.u_id
FROM
messages m
LEFT JOIN
users u
ON
m.sender_id=u.u_id
LEFT JOIN
recipient r
ON
r.m_id=m.m_id
WHERE
(m.sender_id=01 OR m.sender_id=02 ) and
(r.recipient_id=01 OR r.recipient_id=02)
Комментарии:
1. Как должен выглядеть результирующий набор
2. Пожалуйста, я обновил свой вопрос, надеюсь, это прояснит
Ответ №1:
Вот одно из решений. Это работает путем фильтрации сообщений, которыми обмениваются пользователи 01 и 02, и отображения только тех, которые относятся к вошедшему в систему пользователю:
SELECT m.sender_id, m.recipient_id, m.Body, u_sender.Name as Sender,
u_recipient.Name as Recipient, sender_deleted, recipient_deleted
FROM messages m
JOIN recipient r ON (m.m_id=r.m_id)
JOIN user u_sender ON (m.sender_id=u_sender.u_id)
JOIN user u_recipient ON (r.recipient_id=u_recipient.u_id)
WHERE
m.sender_id IN (01,02)
AND
r.recipient_id ON (01,02)
AND
((m.sender_id=<id> AND m.sender_deleted='no')
OR
(r.recipient_id=<id> AND r.recipient_deleted='no'))
Вы должны заменить <id>
идентификатор зарегистрированного пользователя (01 или 02)
Вы можете, конечно, изменить возвращаемые поля, чтобы отобразить то, что вам нужно.
Надеюсь, это поможет!
Комментарии:
1. Да, спасибо @Mariano .. это сработало, но не повлияет ли это на производительность при большом количестве строк?
2. Привет @George. Я думаю, что этот запрос будет выполняться хорошо, если установлены правильные индексы. Например,
users.u_id
должен быть первичный ключ.messages
должно иметьm_id
значение PK. Дляrecipient
значение PK зависит от того, можете ли вы отправить сообщение нескольким получателям. В этом случае PK для получателей должен быть(m_id,recipient_id)
Вы можете создать индексы для sender_deleted / recipient_deleted, чтобы увеличить время поиска. Обратите внимание, что, не используя левые (внешние) соединения, движку приходится намного меньше проходить. Как всегда, MySQLEXPLAIN
может вам в этом очень помочь, вы можете поиграть и посмотреть, что получится.3. Спасибо @Mariano, я понял каждый указанный пункт, и я уже использую тот же процесс, о котором вы упомянули. Но, исходя из вашего последнего пункта, вы имеете в виду, что лучше запретить использование левых (внешних) объединений? это в моем случае выше
4. Да, я думаю, что лучше избегать их. ВНЕШНИЕ соединения полезны, но у них есть по крайней мере 2 недостатка: 1) они не так эффективны, как внутренние соединения, потому что движку приходится приводить записи, которые совпадают, а также записи, которые не совпадают, и 2) легко установить условия таким образом, чтобы привести больше записей, чем вы действительно намереваетесь. Вы должны быть очень осторожны при настройке условий ON / WHERE для внешних соединений. Если это не очень очевидно (т. Е. Используя левое соединение, чтобы избежать использования NOT IN), я стараюсь использовать внутренние.
Ответ №2:
Следующий запрос возвращает столбцы, размещенные в вопросе для требуемых сообщений:
SELECT
msg_details.sender_id,
msg_details.Body,
u.Name,
u.u_id
FROM users u
INNER JOIN messages msg_details ON u.u_id = msg_details.sender_id
LEFT JOIN messages m ON msg_details.m_id = m.m_id
LEFT JOIN recipient r ON msg_details.m_id = r.m_id
WHERE (m.sender_id = <user_id> AND m.sender_deleted = 'no')
OR (r.recipient_id = <user_id> AND r.recipient_deleted = 'no');
Замените user_id
на текущее user_id
.