#mysql #sql
#mysql #sql
Вопрос:
Я столкнулся с некоторой проблемой агрегации groupby в моем запросе объединения ниже:
SELECT chat_tbl.chatrec_id,
chat_tbl.senderid,
chat_tbl.receiverid,
chat_tbl.msg,
chat_tbl.chat_time,
chat_tbl.chatuser_strid,
chatuser_link_tbl.str_id,
chatuser_link_tbl.modifytime
FROM chat_tbl
INNER JOIN chatuser_link_tbl ON chat_tbl.chatuser_strid = chatuser_link_tbl.str_id
AND (chat_tbl.senderid=393 OR chat_tbl.receiverid=393)
GROUP by chat_tbl.chatuser_strid
ORDER by chatuser_link_tbl.modifytime DESC
Я знаю, что могу отключить only_full_group_by
настройку, выполнив следующее:
set global sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
set session sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
Но это неправильный метод, он отменяет настройки, и это снова удаляется после каждого перезапуска сервера, поэтому я хочу исправить свой запрос. Пожалуйста, кто-нибудь может помочь мне правильно написать этот запрос объединения из 3 таблиц.
Заранее спасибо.
Обновление 1: я использую этот запрос, чтобы перечислить все чаты, выполняемые текущим пользователем с другими пользователями.
У меня есть 2 таблицы для этого, в chatuser_link_tbl есть ссылка на чат, созданная между 2 пользователями, например, 11-18, 12-22, т. Е. объединены 2 идентификатора пользователя с dash — и таблица чата содержит фактические данные чата.
Я использую group by для группировки всех чатов с использованием chatuser_strid, чтобы получить только одну последнюю запись. Я показываю только последнее сообщение чата с указанием даты и времени.
Короче говоря, это то же самое, что список чатов WhatsApp (первый домашний экран) или список чатов Facebook Messenger. Которая отображает данные пользователя с их последним сообщением в чате.
Комментарии:
1. В вашем
SELECT
списке могут быть только значения, которые являются либо агрегатной функцией (например,MAX()
,SUM()
,COUNT()
и т.д.), Либо поля, которые присутствуют в вашихGROUP BY
, при использовании сгруппированных запросов.2. Почему вы вообще используете
GROUP BY
предложение здесь?3. @Qirel Не могли бы вы переписать этот запрос с вашими предложениями, чтобы сделать его правильным?
4. Я предлагаю вам взять руководство по SQL и понять, что все делает. Вы понимаете, что
GROUP BY
делает? Потому что я не понимаю, почему вы использовали ее здесь. И я готов поспорить, что если вы удалите ее, вы добьетесь некоторого прогресса..5. Сначала вы должны объяснить значение запроса. Чего именно вы пытаетесь достичь, и какие поля обеих таблиц вам нужно извлечь для вашего приложения
Ответ №1:
Поскольку ваш запрос предназначен для работы с одним пользователем (отправителем или получателем, равным 393), вы можете просто удалить group by и добавить ограничение
SELECT chat_tbl.chatrec_id,
chat_tbl.senderid,
chat_tbl.receiverid,
chat_tbl.msg,
chat_tbl.chat_time,
chat_tbl.chatuser_strid,
chatuser_link_tbl.str_id,
chatuser_link_tbl.modifytime
FROM chat_tbl
INNER JOIN chatuser_link_tbl ON chat_tbl.chatuser_strid = chatuser_link_tbl.str_id
AND (chat_tbl.senderid=393 OR chat_tbl.receiverid=393)
ORDER by chatuser_link_tbl.modifytime DESC
LIMIT 1
Комментарии:
1. Если вы делали это только для тестирования, и вы хотите, чтобы ваш окончательный запрос выполнялся для всех пользователей. Вы можете использовать оконные функции (LAST_VALUE) или боковое соединение, если ваша версия MySQL поддерживает любую из них. Если это так, я могу расширить свой ответ.
2. Этот запрос выдаст только отдельные записи, я хочу, чтобы все записи таблицы chat имели либо идентификатор получателя = 393, либо идентификатор отправителя = 393. Например, вы могли бы общаться с несколькими пользователями, а не только с одним пользователем. Например, проверьте Facebook messanger, где отображается список всех пользователей и их последнее сообщение, с которым вы общались. надеюсь, теперь это ясно.
3. В этом случае ответ Гордона не должен быть именно тем, что вам нужно. Единственная проблема может возникнуть из-за chatuser_strid, который будет отображаться дважды для пар (например, 11-22 и 22-11)
Ответ №2:
Я думаю, вы хотите использовать для этого оконные функции:
SELECT *
FROM (SELECT c.*, cl.str_id, cl.modifytime,
ROW_NUMBER() OVER (PARTITION BY c.chat_user_strid ORDER BY cul.modifytime DESC)
FROM chat_tbl c JOIN
chatuser_link_tbl cul
ON c.chatuser_strid = cul.str_id AND
393 IN (c.senderid, c.receiverid)
) c
WHERE seqnum = 1;
Ответ №3:
Я исправил проблему самостоятельно. Приведенный ниже запрос сработал для меня, чтобы получить желаемый результат.
Мне помоглоANY_VALUE.
SELECT chat_tbl.chatuser_strid, ANY_VALUE(chat_tbl.chatrec_id),ANY_VALUE(chat_tbl.senderid),ANY_VALUE(chat_tbl.receiverid),ANY_VALUE(chat_tbl.msg),ANY_VALUE(chat_tbl.chat_time), ANY_VALUE(chatuser_link_tbl.str_id)
FROM chat_tbl
INNER JOIN chatuser_link_tbl
ON chat_tbl.chatuser_strid = chatuser_link_tbl.str_id AND (chat_tbl.senderid=".$userid." OR chat_tbl.receiverid=".$userid.")
GROUP by chat_tbl.chatuser_strid
ORDER by ANY_VALUE(chatuser_link_tbl.modifytime) DESC