Я пытаюсь получить последнее сообщение из таблицы сообщений, сгруппированной по отправителю или получателю (в зависимости от того, какое из них существует, а какое является последним.), А затем ВЛЕВО присоединиться к имени пользователя из другой таблицы (пользователя).
Допустим, я хочу, чтобы все сообщения были отправлены и получены пользователем с идентификатором 12 (это я), а затем СЛЕДУЮЩИМ СОЕДИНЕНИЕМ имени пользователя из другой таблицы на основе того, с кем я веду беседу.
PHP:
$userId = 12;
MySQL
SELECT
message.*,
user.username
FROM
message,
(
SELECT MAX(id) as lastid
FROM message
WHERE (message.recipient = `$userId` OR message.sender = `$userId`)
GROUP BY CONCAT(
LEAST(message.recipient,message.sender),
'.',
GREATEST(message.recipient, message.sender)
)
) as conversations
LEFT JOIN user on 1 = user.id
WHERE message.id = conversations.lastid
ORDER BY message.datesent DESC
Этот код работает просто отлично, но LEFT JOIN, очевидно, не имеет смысла, поскольку он всегда использует 1 в качестве сравнения, но он должен использовать отправителя или получателя (в зависимости от того, что $userId
.
Когда я просто заменяю 1
на message.sender для примера, я получаю только Unknown column 'message.sender' in 'on clause'
.
У меня уже работает другой запрос, но он ужасно медленный (32 секунды):
SELECT m.*, user_receive.username, user_receive.avatar, user_receive.rank
FROM message AS m
INNER JOIN
(
SELECT
LEAST(sender, recipient) AS sender,
GREATEST(sender, recipient) AS recipient,
MAX(id) AS max_id
FROM message
GROUP BY
LEAST(sender, recipient),
GREATEST(sender, recipient)
) AS result
ON LEAST(m.sender, m.recipient) = result.sender AND
GREATEST(m.sender, m.recipient) = result.recipient AND
m.id = result.max_id
LEFT JOIN user AS user_send on result.sender = user_send.id LEFT JOIN user AS user_receive on result.recipient = user_receive.id
WHERE m.sender = 1 OR m.recipient = 1
ORDER BY m.datesent DESC;
Другой запрос намного быстрее (20 мс).
Любые идеи Как правильно использовать LEFT JOIN в первом / быстром запросе, чтобы получить имя пользователя?
EDIT:
Создать таблицы:
CREATE TABLE `message` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(100) DEFAULT NULL,
`body` mediumtext NOT NULL,
`recipient` int(11) NOT NULL,
`sender` int(11) NOT NULL,
`additional` varchar(50) DEFAULT NULL,
`datesent` int(11) NOT NULL,
`seen` tinyint(4) NOT NULL DEFAULT '0',
`hidden` tinyint(4) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `recipient` (`recipient`,`datesent`,`seen`,`hidden`),
KEY `sender` (`sender`)
) ENGINE=InnoDB AUTO_INCREMENT=1122 DEFAULT CHARSET=utf8mb4;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
`rank` varchar(20) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'user',
`avatar` varchar(100) COLLATE utf8_unicode_ci DEFAULT 'default',
PRIMARY KEY (`id`),
KEY `username` (`username`),
KEY `avatar` (`avatar`)
) ENGINE=InnoDB AUTO_INCREMENT=214 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
EXPLAIN для быстрого запроса:
+---+---------+------------+------+-------------+------------------+------------------+------+----------------------+-----+--------+----------------------------------------------------------------------------------+
| 1 | PRIMARY | <derived2> | NULL | ALL | NULL | NULL | NULL | NULL | 458 | 100.00 | Using where; Using temporary; Using filesort |
+---+---------+------------+------+-------------+------------------+------------------+------+----------------------+-----+--------+----------------------------------------------------------------------------------+
| 1 | PRIMARY | user | NULL | const | PRIMARY | PRIMARY | 4 | const | 1 | 100.00 | NULL |
| 1 | PRIMARY | message | NULL | eq_ref | PRIMARY | PRIMARY | 4 | conversations.lastid | 1 | 100.00 | NULL |
| 2 | DERIVED | message | NULL | index_merge | recipient,sender | recipient,sender | 4,4 | NULL | 458 | 100.00 | Using sort_union(recipient,sender); Using where; Using temporary; Using filesort |
+---+---------+------------+------+-------------+------------------+------------------+------+----------------------+-----+--------+----------------------------------------------------------------------------------+
ОБЪЯСНИТЕ для медленного запроса:
+---+---------+--------------+------+-------------+--------------------------+------------------+------+-----------------------+------+--------+-----------------------------------------------------------------+
| 1 | PRIMARY | m | NULL | index_merge | PRIMARY,recipient,sender | sender,recipient | 4,4 | NULL | 458 | 100.00 | Using sort_union(sender,recipient); Using where; Using filesort |
+---+---------+--------------+------+-------------+--------------------------+------------------+------+-----------------------+------+--------+-----------------------------------------------------------------+
| 1 | PRIMARY | <derived2> | NULL | ref | <auto_key0> | <auto_key0> | 21 | func,func,dbname.m.id | 10 | 100.00 | Using where; Using index |
| 1 | PRIMARY | user_send | NULL | eq_ref | PRIMARY | PRIMARY | 4 | result.sender | 1 | 100.00 | Using where; Using index |
| 1 | PRIMARY | user_receive | NULL | eq_ref | PRIMARY | PRIMARY | 4 | result.recipient | 1 | 100.00 | Using where |
| 2 | DERIVED | message | NULL | ALL | NULL | NULL | NULL | NULL | 1122 | 100.00 | Using temporary; Using filesort |
+---+---------+--------------+------+-------------+--------------------------+------------------+------+-----------------------+------+--------+-----------------------------------------------------------------+