Есть ли способ, которым я могу ВЫБИРАТЬ и ОБЪЕДИНЯТЬ разные запросы?

#mysql #sql

Вопрос:

Я использую MYSQL, и у меня есть таблица сообщений, как показано ниже.

ID parent_id sender_id receiver_id Содержание прочитано sender_deleted receiver_deleted создано
18 0 6 1 testab 0 0 0 2021-10-28 01:13:42
19 18 6 1 testcd 0 0 0 2021-10-28 01:14:55

Я пытаюсь объединить два запроса в один. Выбор и подсчет, где прочитанное значение равно 0.

Этот запрос выбирает запрос.

 SELECT * FROM message 
    WHERE (sender_id = 1 OR receiver_id = 1) AND (id = 18 OR parent_id = 18);
 

И этот запрос является запросом подсчета.

 SELECT COUNT(id) FROM message 
     WHERE (sender_id = 1 OR receiver_id = 1) 
       AND (id = 18 OR parent_id = 18) AND (readed = 0);
 

Я пытаюсь объединить эти два, используя ЛЕВОЕ СОЕДИНЕНИЕ.

 SELECT a.id, a.parent_id, a.content, COUNT(b.id) AS unreaded_message 
  FROM message a 
  LEFT JOIN message c ON a.id = c.id AND (readed = 0) 
 GROUP BY A.ID, A.Date 
 ORDER BY a.id;
 

Но я получаю ошибку, как показано ниже.

 ERROR 1054 (42S22): Unknown column 'b.id' in 'field list'
 

Есть ли способ, которым я могу оставить запрос на подсчет количества соединений?

Ответ №1:

Я замечаю эти проблемы при тестировании запроса:

  1. Неправильный псевдоним b.id для COUNT() . Вот где ошибка.
  2. Несуществующая таблица A.Date from message . Основываясь на вашем примере таблицы, у вас нет столбца с именем as Date . Вместо этого у вас есть столбец с именем created , в котором хранится дата время.
  3. Сам запрос несовместим с sql_mode=only_full_group_by . only_full_group_by Начиная с MySQL версии 5.7.5, этот параметр включен по умолчанию по очень веской причине: «если режим выключен, сервер может выбирать любое значение из каждой группы, поэтому, если они не совпадают, выбранные значения являются недетерминированными, что, вероятно, не то, что выхотите (см.: «Обработка MySQL Group By» документы.

Теперь, если я не ошибаюсь, content сохраняет текстовые сообщения, правильно? И поскольку id=19 parent is id=18 , он должен быть в той же строке, а общее количество непрочитанных сообщений равно 2 . Я не уверен, что это то, что вы действительно ищете, но я опубликую два запроса; один — для решения вашей текущей проблемы, а другой — чтобы предположить, что это, возможно, то, что вы ищете.

Для вашей текущей проблемы вы можете достичь желаемого результата без самостоятельного объединения, и вместо использования COUNT() вы можете использовать SUM() CASE выражение with, как показано ниже:

 SELECT id, parent_id, content, 
      SUM(CASE WHEN readed=0 THEN 1 ELSE 0 END) AS unreaded_message
FROM message
GROUP BY id, parent_id, content;
 

COUNT() будет принимать каждую строку в результате запроса в зависимости от ваших условий. Замена SUM() с CASE выражением здесь просто сообщает запросу:

 SUM(CASE WHEN readed=0 THEN 1 ELSE 0 END) AS unreaded_message
   -- if the readed column is 0 (zero) then give it 1, else give it 0 then add them up.
 

Второе предложение, которое у меня есть, это предположим, что у вас есть больше строк в таблице, подобной этой:

ID parent_id sender_id receiver_id Содержание прочитано sender_deleted receiver_deleted создано
18 0 6 1 testab 1 0 0 2021-10-28 01:13:42
19 18 6 1 testcd 1 0 0 2021-10-28 01:14:55
20 18 6 1 testde 0 0 0 2021-10-28 01:15:05
21 0 6 1 testfg 0 0 0 2021-10-28 02:34:11
22 21 6 1 тесты 0 0 0 2021-10-28 02:44:01

При id наличии 18,19 обоих readed=1 запросов запрос, который у вас есть, и тот, который я предложил выше, вернет результат, подобный этому:

ID parent_id Содержание unreaded_message
18 0 testab 0
19 18 testcd 0
20 18 testde 1
21 0 testfg 1
22 21 тесты 1

Но у меня такое чувство, что вы, вероятно, хотите что-то вроде этого:

m_id Содержание unreaded_message
18 testde 1
21 testgf
testhi
2

Если это возможно, вы можете просто запустить этот запрос:

 SELECT CASE WHEN parent_id=0 THEN id ELSE parent_id END AS m_id, 
        GROUP_CONCAT(CASE WHEN readed=0 
                          THEN content ELSE '' END 
                      ORDER BY readed, id SEPARATOR 'rn' ) AS contents,
        SUM(CASE WHEN readed=0 THEN 1 ELSE 0 END) AS unreaded_message
FROM message
GROUP BY m_id;
 

Демонстрационная скрипка

Комментарии:

1. Большое вам спасибо. Это то, чего я действительно хотел.

Ответ №2:

Вы используете в запросе псевдоним B в параметре «ПОДСЧЕТ». Вам нужно использовать псевдоним A или C, как в этом примере:

 SELECT a.id, a.parent_id, a.content, COUNT(c.id) AS unreaded_message 
FROM message a 
LEFT JOIN message c ON a.id = c.id AND (readed = 0) 
GROUP BY A.ID, A.Date 
ORDER BY a.id;