MySQL: Получить последнее сообщение от отправителя или получателя и присоединиться к ID - PullRequest
0 голосов
/ 06 февраля 2020

Я пытаюсь получить последнее сообщение из таблицы сообщений, сгруппированной по отправителю или получателю (в зависимости от того, какое из них существует, а какое является последним.), А затем ВЛЕВО присоединиться к имени пользователя из другой таблицы (пользователя).

Допустим, я хочу, чтобы все сообщения были отправлены и получены пользователем с идентификатором 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                                 |
    +---+---------+--------------+------+-------------+--------------------------+------------------+------+-----------------------+------+--------+-----------------------------------------------------------------+
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...