MySQL-запрос с двумя разными инструкциями в одном столбце

Я пытаюсь написать запрос 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?

user1191247 10.06.2024 10:05

Мне нужно, чтобы ближайшее значение было равно 120 или не превышало 120. Оборудование регистрирует данные с интервалом примерно в 5–7 минут, и я не могу это контролировать, я просто извлекаю данные из живого файла CSV на удаленном сервере. На данный момент я делаю два выбора и рисую графики по отдельности, но хотел бы просто сделать один выбор sql, чтобы получить данные, поэтому, когда я передаю выбор графическому плагину, я получаю оба варианта на одном графике.

Peter_Brown_USA 10.06.2024 17:07
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
0
3
93
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете добиться этого, создав два подзапроса и затем объединив их.

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. Спасибо

Peter_Brown_USA 10.06.2024 17:20

Ваши два запроса должны вызывать ошибки, поскольку soc отсутствует в предложении GROUP BY или в агрегатной функции. Тот факт, что они «работают», означает, что у вас отключена ONLY_FULL_GROUP_BY , а это плохо. Пожалуйста, прочитайте Обработка GROUP BY в MySQL , особенно часть, объясняющую недетерминированные результаты.

Образец данных

Дата_MySQL Minutes_Since_Midnight соц 2024-06-01 108 13 2024-06-01 115 9 хочу это как <= 120 2024-06-01 121 12 2024-06-01 413 8 2024-06-01 419 7 хочу это как <= 420 2024-06-01 423 9 2024-06-02 118 16 2024-06-02 120 15 хочу это как <= 120 2024-06-02 413 18 2024-06-02 420 17 хочу это как <= 420

Принятый в настоящее время ответ выведет:

Дата_MySQL Сокама сокамб 2024-06-01 13 13 2024-06-02 16 18

Это неверно, поскольку он просто возвращает максимум 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;

Выходы:

Дата_MySQL Сокама сокамб 2024-06-01 9 7 2024-06-02 15 17

Другой способ — использовать условную агрегацию, чтобы получить два максимальных значения времени (<= 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<>рабочий пример.

Другие вопросы по теме