#mysql #sql #count #mariadb #aggregate-functions
#mysql #sql #количество #mariadb #агрегатные функции
Вопрос:
Я столкнулся с довольно странной проблемой с моим экземпляром MariaDB при использовании инструкции IN.
Например, если мне нужна информация о некоторых совокупных объемах продуктов, которые продают торговые устройства, я выполняю запрос следующим образом:
SELECT
SUM( l.volume_given ) AS volume,
COUNT( l.id ) AS sessions,
l.order AS container,
MIN( dev.NAME ) AS NAME,
MIN( dev.address ) AS address,
dev.id AS id
FROM
devices AS dev
JOIN my_logs AS l ON dev.id = l.device_id
WHERE
l.created_at >= '2020-08-31 21:00:00'
AND l.created_at <= '2020-10-21 21:00:00'
AND l.water_type = 0
AND l.device_id IN (*some 20 IDs here*)
GROUP BY container
ORDER BY sessions DESC;
Странно то, что, например, для ID = 114 я получаю только 4 строки для этого устройства из 232 полных строк. Однако, если я выполню тот же запрос, но с
AND l.device_id = 114
Я получаю 44 строки для этого идентификатора, который является его реальным результатом.
То, что я пытался, было:
- пропустите материал JOIN и используйте только
my_logs
table; - попробуйте разные интервалы дат;
- попробуйте аналогичные запросы для других таблиц.
Никакой разницы со всем этим.
У вас есть какие-либо идеи, что проверить? Большое вам спасибо!
Комментарии:
1. Вы агрегируете по
container
. И вашиgroup by
столбцы несовместимы соselect
столбцами. Я удивлен, что запрос работает.2. На самом деле это слегка измененный (путем ОБЪЕДИНЕНИЯ) запрос из серверного приложения Ruby, где он как-то работает.
Ответ №1:
Если я правильно вас понял, вы хотите id
, чтобы в GROUP BY
предложении:
GROUP BY l.order, dev.id
В SQL существует золотое правило, согласно которому все неагрегированные столбцы в SELECT
предложении должны повторяться в GROUP BY
предложении (если только они функционально не зависят от другого столбца, который принадлежит этому предложению, но это уже другая история).
MySQL был небрежен в этом отношении в ранних версиях, вызывая какое-то нелогичное поведение, которое затем трудно отлаживать, если вы не учитываете это правило. Убедитесь, что всегда включен режим sql ONLY_FULL_GROUP_BY
, поэтому такие проблемы рассматриваются как синтаксические ошибки.
Обратите внимание, что в этом измененном GROUP BY
предложении используются фактические имена столбцов, а не их псевдонимы; это также стандартный SQL (в то время как MySQL допускает иное).
Ответ №2:
Выворачивание наизнанку может ускорить его:
SELECT l2.volume, l2.sessions, l2.container,
dev.NAME, dev.address, dev.id
FROM
(
SELECT l.device_id, l.order AS container,
SUM( l.volume_given ) AS volume,
COUNT(*) AS sessions
FROM logs AS l
WHERE l.created_at >= '2020-08-31 21:00:00'
AND l.created_at <= '2020-10-21 21:00:00'
AND l.water_type = 0
AND l.device_id IN (*some 20 IDs here*)
GROUP BY l.device_id, container
) AS l2
JOIN devices AS dev ON dev.id = l2.device_id
ORDER BY l2.sessions DESC
И это может исправить перерасчет count (*).
Я рекомендую
INDEX(water_type, device_id)
INDEX(water_type, created_at)