Я пытаюсь написать запрос MySQL для построения графиков, график предназначен для одного столбца, но в разное время дня.
У меня есть таблица, которая измеряет состояние заряда большой батареи, и я хочу создать таблицу для построения графика, где я могу получить SoC примерно в 2 часа ночи и 7 утра.
Это один из SELECT, который я использую в 2 часа ночи.
SELECT luxpower.`Date_MySQL`,
luxpower.`soc`
FROM luxpower
WHERE luxpower.`Minutes_Since_Midnight` <= 120
GROUP BY luxpower.`Date_MySQL`
и это SELECT, который я использую в 7 утра
SELECT luxpower.`Date_MySQL`,
luxpower.`soc`
FROM luxpower
WHERE luxpower.`Minutes_Since_Midnight` <= 420
GROUP BY luxpower.`Date_MySQL`
Мне бы хотелось объединить в один запрос с soc как два разных псевдонима, что-то вроде этого (что не работает)
SELECT luxpower.`Date_MySQL`,
luxpower.`soc` as socama (FROM luxpower WHERE luxpower.`Minutes_Since_Midnight` <= 120 GROUP BY luxpower.`Date_MySQL`)
AND
SELECT luxpower.`Date_MySQL`,
luxpower.`soc` as socamb (FROM luxpower WHERE luxpower.`Minutes_Since_Midnight` <= 420 GROUP BY luxpower.`Date_MySQL`)
Я хочу, чтобы набор записей был похож на
Date_MySQL,socama ,socamab
2024-06-01,10,7
2024-06-02,15,17
2024-06-03,23,44
2024-06-04,10,32
Спасибо
Мы не можем быть уверены на 100 %, поскольку вы не включили структуру таблицы или примеры данных, но ваш подход выглядит недетерминированным. Пожалуйста, прочитайте Обработка GROUP BY в MySQL. Как часто вы заходите soc?
Мне нужно, чтобы ближайшее значение было равно 120 или не превышало 120. Оборудование регистрирует данные с интервалом примерно в 5–7 минут, и я не могу это контролировать, я просто извлекаю данные из живого файла CSV на удаленном сервере. На данный момент я делаю два выбора и рисую графики по отдельности, но хотел бы просто сделать один выбор sql, чтобы получить данные, поэтому, когда я передаю выбор графическому плагину, я получаю оба варианта на одном графике.






Вы можете добиться этого, создав два подзапроса и затем объединив их.
SELECT query1.`Date_MySQL`,
query1.`soc` as socama,
query2.`soc` as socamb FROM (
SELECT `Date_MySQL`,
MAX(`soc`) as soc
FROM luxpower
WHERE `Minutes_Since_Midnight` <= 120
GROUP BY `Date_MySQL`) query1 JOIN (
SELECT `Date_MySQL`, MAX(`soc`) as soc
FROM luxpower
WHERE `Minutes_Since_Midnight` <= 420
GROUP BY `Date_MySQL`) query2 ON query1.`Date_MySQL` = query2.`Date_MySQL` ORDER BY query1.`Date_MySQL`;
Первый запрос проверяет, где Minutes_Since_Midnight меньше или равен 2 часам утра, а второй проверяет, где он меньше или равен 7 утра.
Подробнее можно прочитать здесь https://dev.mysql.com/doc/refman/8.4/en/all-subqueries.html
Спасибо, отлично работает и очень помогает мне с этими более сложными операторами sql. Спасибо
Ваши два запроса должны вызывать ошибки, поскольку soc отсутствует в предложении GROUP BY или в агрегатной функции. Тот факт, что они «работают», означает, что у вас отключена ONLY_FULL_GROUP_BY , а это плохо. Пожалуйста, прочитайте Обработка GROUP BY в MySQL , особенно часть, объясняющую недетерминированные результаты.
Образец данных
Принятый в настоящее время ответ выведет:
Это неверно, поскольку он просто возвращает максимум soc в данной группе, а не soc для максимума Minutes_Since_Midnight в группе.
Есть много способов добиться этого, один из них — использование коррелированных подзапросов в списке выбора:
SELECT l.Date_MySQL,
(
SELECT soc FROM luxpower
WHERE Date_MySQL = l.Date_MySQL
AND Minutes_Since_Midnight <= 120
ORDER BY Minutes_Since_Midnight DESC LIMIT 1
) AS socama,
(
SELECT soc FROM luxpower
WHERE Date_MySQL = l.Date_MySQL
AND Minutes_Since_Midnight <= 420
ORDER BY Minutes_Since_Midnight DESC LIMIT 1
) AS socamb
FROM luxpower l
GROUP BY l.Date_MySQL;
Выходы:
Другой способ — использовать условную агрегацию, чтобы получить два максимальных значения времени (<= 120 и <= 420), а затем использовать их для обратного соединения, чтобы получить soc:
SELECT t1.Date_MySQL, l1.soc AS socama, l2.soc AS socamb
FROM (
SELECT
Date_MySQL,
MAX(IF(Minutes_Since_Midnight <= 120, Minutes_Since_Midnight, NULL)) AS t_120,
MAX(Minutes_Since_Midnight) AS t_420
FROM luxpower
WHERE Minutes_Since_Midnight <= 420
GROUP BY Date_MySQL
) AS t1
JOIN luxpower l1 ON t1.Date_MySQL = l1.Date_MySQL AND t1.t_120 = l1.Minutes_Since_Midnight
JOIN luxpower l2 ON t1.Date_MySQL = l2.Date_MySQL AND t1.t_420 = l2.Minutes_Since_Midnight;
Тот же результат, что и предыдущий запрос.
Вы также можете добиться того же, используя оконную функцию ROW_NUMBER(), а затем условное агрегирование для поворота результата:
WITH t1 AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY Date_MySQL ORDER BY Minutes_Since_Midnight <= 120 DESC, Minutes_Since_Midnight DESC) AS rn2,
ROW_NUMBER() OVER (PARTITION BY Date_MySQL ORDER BY Minutes_Since_Midnight DESC) AS rn7
FROM luxpower
WHERE Minutes_Since_Midnight <= 420
)
SELECT
Date_MySQL,
MAX(IF(rn2 = 1, soc, NULL)) AS socama,
MAX(IF(rn7 = 1, soc, NULL)) AS socamb
FROM t1
WHERE rn2 = 1 OR rn7 = 1
GROUP BY Date_MySQL;
/* or */
WITH t1 AS (
SELECT Date_MySQL, Minutes_Since_Midnight AS MSM, soc,
ROW_NUMBER() OVER (PARTITION BY Date_MySQL, IF(Minutes_Since_Midnight <= 120, 't_120', 't_420') ORDER BY Minutes_Since_Midnight DESC) AS rn
FROM luxpower
WHERE Minutes_Since_Midnight <= 420
)
SELECT
Date_MySQL,
MAX(IF(rn = 1 AND MSM <= 120, soc, NULL)) AS socama,
MAX(IF(rn = 1 AND MSM > 120, soc, NULL)) AS socamab
FROM t1
WHERE rn = 1
GROUP BY Date_MySQL;
Опять тот же результат.
Вот db<>рабочий пример.