Мой английский не так хорош, но я попытаюсь объяснить проблему.
У меня есть три таблицы: одна называется Accounts, одна называется Accounts_Profiles, а другая называется Accounts_Messages. Моя цель — показать последних пользователей, которым вошедший в систему пользователь ($login_user_id) отправил сообщение.
Мои таблицы в основном состоят из этого:
Accounts
идентификатор, имя, электронная почта, нивел, проверка
Accounts_Profiles
идентификатор, user_id, статус
Accounts_Messagens
идентификатор, отправитель (int), получатель (int)
Мой запрос в настоящее время выглядит так:
SELECT DISTINCT Accounts.id, Accounts.email, Accounts.name, Accounts.username, Accounts.avatar, Accounts.nivel, Accounts.verification FROM Accounts JOIN Accounts_Messages ON Accounts.id = Accounts_Messages.receiver ORDER BY Accounts_Messages.id DESC;
В CodeIgniter/PHP это выглядит так:
/*
With the $this->db->distinct() I make sure that the users shown will not be repeated - It works!
*/
$this->db->distinct();
$this->db->select(
array(
"Accounts.id id",
"Accounts.email email",
"Accounts.name name",
"Accounts.username username",
"Accounts.avatar avatar",
"Accounts.nivel nivel",
"Accounts.verification verification",
"Accounts_Profiles.status online",
"(SELECT IF(COUNT(ACM.id) > 0, COUNT(ACM.id), null) FROM Accounts_Messages ACM WHERE ACM.receiver = '$login_user_id' AND ACM.sender = 'Accounts.id' AND ACM.is_read = '0') unread"
)
);
/*
Here I exclude the $login_user_id from the list, the admin users and also those who have not verified the account - It works!
*/
$this->db->join(
"Accounts_Profiles",
"Accounts_Profiles.user_id = Accounts.id",
"left"
);
$this->db->where(
array(
"Accounts.id ! = " => $login_user_id,
"Accounts.nivel ! = " => 'administrator',
"Accounts.verification ! = " => 'false'
)
);
/*
Here, I sort messages by last sent. I check who the logged in user sent the last messages to and list those users - This only works on localhost.
*/
$this->db->join(
"Accounts_Messages",
"Accounts.id = Accounts_Messages.receiver",
"left"
);
$this->db->order_by(
"Accounts_Messages.id", 'DESC'
);
/*
Returning the result
*/
return $this->db->limit($filters['limit'])->offset($filters['offset'])->get("Accounts")->result();
Проблема: Это работает на локальном хосте, но не работает в производстве. На локальном хосте я использую MySQL. На рабочем сервере я использую MariaDB. Теоретически это не должно иметь никакого значения, так как использованные мной предложения совместимы в обоих случаях.
Я забыл что-то сделать или настроить на рабочем сервере?
Спасибо!
Я пытался добавить это для совести, но это не сработало:$this->db->group_by( "Accounts.id" );
Как видите, в localhost порядок пользователей определяется последним отправленным им сообщением. Это то, что я ожидаю в производстве.
На рабочем сервере упорядочивание происходит по дате создания разговора (я не знаю, как). Это неправильно, так как первые пользователи, с которыми я общаюсь, всегда приходят последними, даже если я отправляю им новое сообщение.
Привет, @NicoHaase! Я проводил одни и те же тесты на одних и тех же машинах не менее 5 лет... Я впервые сталкиваюсь с этой проблемой. Он не отображает ошибки. Сортировка просто не идет как надо. Код абсолютно одинаков в обоих случаях (localhost и live server). Все всегда работало нормально. Я никогда не делал ничего, чтобы работать исключительно с MariaDB.
Можете ли вы запустить запрос SELECT VERSION();
как на локальном, так и на рабочем сервере и сообщить, что говорит каждый из них?
Привет, @BillKarwin! Конечно! MySQL: 8.0.31. MariaDB: 10.1.48-MariaDB-0+deb9u1
Вы пытались выполнить запрос непосредственно к базе данных? И это может показаться глупым вопросом, но вы загружали данные в рабочую базу данных?
Привет, @aynber! Спасибо за вопрос. Да, две базы данных абсолютно одинаковы. Между ними нет различий. Я попытался выполнить запрос через терминал, а также через PhpMyAdmin... он работает только на локальном хосте. :/
И что происходит, когда вы запускаете его в производственной системе? Это дает пустой результат?
Его @NicoHaase! Не возвращает пустые результаты. Он возвращает список с другим порядком, чем тот, который я определил в запросе. Мой запрос должен вернуть последних пользователей, которым я отправил сообщение, в порядке убывания (и это то, что происходит на локальном хосте). Короче говоря, в производстве он сортируется по дате создания разговора, а не по идентификатору сообщения.
Пожалуйста, добавьте все пояснения к вашему вопросу, отредактировав его. Если запрос не выполняется должным образом, когда вы используете что-то вроде phpMyAdmin, мне это не кажется связанным с CodeIgniter. Поделитесь структурой таблицы, образцами данных, запросом и ожидаемым результатом
Спасибо, @NicoHaase! Я уже отредактировал вопрос с тем, что вы упомянули.
Я не могу проверить ваш запрос с MySQL 5.7 или 8.0. Он возвращает ошибку: "ERROR 3065 (HY000): Expression #1 of ORDER BY clause is not in SELECT list, references column 'test.Accounts_Messages.id' which is not in SELECT list; this is incompatible with DISTINCT"
. Та же ошибка возвращается MySQL 5.7. Таким образом, либо вы тестируете другой запрос, чем тот, который вы показываете, либо вы на самом деле не используете эти версии MySQL.
MariaDB не возвращает эту ошибку. Это показывает более общий момент: MariaDB несовместима с MySQL. MariaDB появилась в 2010 году как форк MySQL, но оба продукта изменились настолько, что нам всем следует перестать думать о них как о совместимых. При разработке следует использовать ту же марку и версию, что и в производстве.
Давайте посмотрим, понимаю ли я, что вы пытаетесь сделать здесь. У вас есть user_id ($login_user_id), и вы хотите получить список информации об учетных записях от всех получателей писем с этим идентификатором пользователя, упорядоченных по последним первым? Верно?
Привет, @BillKarwin! Эту проблему совместимости я решил следующим образом: SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY','')); УСТАНОВИТЬ СЕССИЯ sql_mode = (ВЫБЕРИТЕ ЗАМЕНУ (@ @ sql_mode, 'ONLY_FULL_GROUP_BY', ''));
Спасибо всем, кто пытался мне помочь. Я решил проблему. Я отредактирую пост, объясняя, что я сделал, чтобы решить эту проблему.
@JesseGaspar, пожалуйста, рассмотрите возможность полного удаления блока «EDIT 2 - решено» и опубликуйте его как ответ на свой вопрос. Объясню: Stack Overflow — это не форум, а сайт вопросов и ответов. В нем есть раздел «Вопрос» (Q), в котором вы задавали свой вопрос. И в нем есть раздел ответов (A), в котором другие пользователи (или вы сами) могут ответить на ваш вопрос. См. Могу ли я ответить на свой вопрос. Спасибо!
Мне удалось решить проблему, выполнив следующую настройку в запросе:
SELECT Accounts.id, Accounts.email, Accounts.name, Accounts.username, Accounts.avatar, Accounts.nivel, Accounts.verification, Accounts_Messages.id
FROM Accounts
JOIN (
SELECT m_to, MAX(dt_updated) as max_updated
FROM Accounts_Messages
GROUP BY m_to
) last_message
ON Accounts.id = last_message.m_to
JOIN Accounts_Messages
ON Accounts.id = Accounts_Messages.m_to AND Accounts_Messages.dt_updated = last_message.max_updated
GROUP BY Accounts.id, Accounts_Messages.id
ORDER BY last_message.max_updated DESC;
В CodeIgniter это выглядит так:
<?php
/*
With the $this->db->distinct() I make sure that the users shown will not be repeated
*/
$this->db->distinct();
$this->db->select(
array(
"Accounts.id id",
"Accounts.email email",
"Accounts.name name",
"Accounts.username username",
"Accounts.avatar avatar",
"Accounts.nivel nivel",
"Accounts.verification verification",
"Accounts_Messages.id acmid",
"Accounts_Profiles.status online",
"(SELECT IF(COUNT(ACM.id) > 0, COUNT(ACM.id), null) FROM Accounts_Messages ACM WHERE ACM.m_to = '$login_user_id' AND ACM.m_from = 'Accounts.id' AND ACM.is_read = '0') unread"
)
);
/*
Here I exclude the $login_user_id from the list, the admin users and also those who have not verified the account
*/
$this->db->join(
"Accounts_Profiles",
"Accounts_Profiles.user_id = Accounts.id",
"left"
);
$this->db->where(
array(
"Accounts.id ! = " => $login_user_id,
"Accounts.nivel ! = " => 'administrator',
"Accounts.verification ! = " => 'false'
)
);
/*
Here, I sort messages by last sent. I check who the logged in user sent the last messages to and list those users
*/
$this->db->join(
"(SELECT m_to, MAX(dt_updated) as max_updated FROM Accounts_Messages GROUP BY m_to) last_message",
"Accounts.id = last_message.m_to",
'inner'
);
$this->db->join(
"Accounts_Messages",
"Accounts.id = Accounts_Messages.m_to AND Accounts_Messages.dt_updated = last_message.max_updated",
'inner'
);
$this->db->group_by(
"Accounts.id, Accounts_Messages.id"
);
$this->db->order_by(
"last_message.max_updated",
"DESC"
);
?>
"это не работает в продакшене" - что это значит? Что произойдет, если вы запустите его? Есть ли ошибка? Кроме того, вы должны использовать ту же систему баз данных в своей системе разработки, чтобы избежать таких проблем.