Сравните дату предыдущей строки в сгруппированном запросе

Я рассчитываю часы, что температура воздуха ниже 7,22. Я хочу сделать этот расчет на стороне SQL.

У меня есть следующая таблица

CREATE TABLE datas (
  id INT,
  air_temperature DOUBLE(8,2),
  created_at TIMESTAMP
);

INSERT INTO datas (id, air_temperature, created_at) VALUES (1, 6.50, '2020-12-01 23:45:02');
INSERT INTO datas (id, air_temperature, created_at) VALUES (2, 6.50, '2020-12-02 03:45:02');
INSERT INTO datas (id, air_temperature, created_at) VALUES (3, 6.92, '2020-12-02 04:00:02');
INSERT INTO datas (id, air_temperature, created_at) VALUES (4, 6.99, '2020-12-02 04:15:02');
INSERT INTO datas (id, air_temperature, created_at) VALUES (5, 7.45, '2020-12-02 04:30:02');
INSERT INTO datas (id, air_temperature, created_at) VALUES (6, 7.34, '2020-12-02 04:45:02');
INSERT INTO datas (id, air_temperature, created_at) VALUES (7, 7.10, '2020-12-02 05:00:02');
INSERT INTO datas (id, air_temperature, created_at) VALUES (8, 7.00, '2020-12-02 05:20:02');
INSERT INTO datas (id, air_temperature, created_at) VALUES (9, 7.12, '2020-12-02 07:15:02');

Интервал данных может быть любым.

Что я хочу получить

date            ch
2020-12-01      1
2020-12-02      3.083
2020-12-03      {calculatedValue}
2020-12-04      {calculatedValue}

Правила

  • если предыдущей строки нет, мы принимаем это за 1 час.

  • Если там есть; берем разницу двух дат. НО если выше чем 1 час, мы принимаем это как 1 час.

Как значение 2020-12-02 равно 3,083?

rowId 2 = take ch as 60 minutes (there's no previous row to compare, so take as 60 minutes. related to rule-1).
rowId 3 = take ch as 15 minutes. (the difference between the date of previous data and the date of current data)
rowId 4 = take ch as 15 minutes (same as rowId 3)
rowId 5 = take ch as 0 (it's not below 7.22)
rowId 6 = take ch as 0 (it's not below 7.22)
rowId 7 = take ch as 15 minutes (same as rowId 3)
rowId 8 = take ch as 20 minutes (same as rowId 3)
rowId 9 = take ch as 60 minutes (previous date is higher than 60 minutes. so take as 60 minutes. related to rule-2)

total minutes of day / 60 = 185 / 60 = 3.083 hours

Если я получу предыдущую дату значения, я могу сравнить и вычислить, но я не знаю, как я могу получить предыдущую строку при использовании группы.

Я думал что-то вроде этого, но я не уверен, как можно применить правила выше.

SELECT
    DATE_FORMAT(created_at, '%d-%m-%Y') as `date`,
    SUM((CASE WHEN air_temperature < 7.22 THEN (apply second rule here) ELSE 0 END)) as ch
FROM datas
GROUP BY `date`

Обновлено: dbfiddle

Какая у вас версия MySQL? потому что у 8.0 ЛИДЕР

Luuk 12.12.2020 17:04

@Luuk уже 8, я могу использовать эти функции

akcoban 12.12.2020 17:08

Попробуйте и покажите, на что вы способны. (Тогда мы будем знать, где ваша настоящая проблема)

Luuk 12.12.2020 17:09

Неясно, когда ch 0.15 или ch 0.20, также вы не предоставили подробностей о том, как вычисляется это значение 3.05 в вашем примере, и из примера неясно, откуда оно берется... Также структура таблицы (и имя таблицы! ) и некоторые примеры данных с желаемым результатом очень помогут в решении вашей проблемы. Но задача SO не в решении вашей проблемы, а в том, чтобы помочь ВАМ решить вашу собственную проблему.

Luuk 12.12.2020 17:23

@Клубничка, прости, я пропустил. Я добавил dbfiddle, этого достаточно?

akcoban 12.12.2020 17:46

@ Луук, ты прав. Я попытался уточнить это.

akcoban 12.12.2020 18:06
Освоение архитектуры микросервисов с 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
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
1
7
116
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Вы можете использовать LEAD(), чтобы получить следующий created_at. Затем используйте арифметику, чтобы ограничить разницу до 60:

SELECT DATE_FORMAT(created_at, '%d-%m-%Y') as `date`,
       SUM( COALESCE(LEAST(TIMESTAMPDIFF(minute, created_at, next_created_at), 60)), 60) / 60 as hours
FROM (SELECT d.*,
             LEAD(created_at) OVER (ORDER BY created_at) as next_created_at
      FROM datas d
     ) d
WHERE air_temperature < 7.22
GROUP BY `date`

Вы выводите 2.0833, желаемый вывод 3.0833. Кто может объяснить разницу?

Luuk 12.12.2020 18:21

Спасибо за ответ! Я добавил новые данные для 2020-12-01 23:45:02. Теперь он правильно вычисляет 2020-12-02. но 2020-12-01 получает значение null, оно должно быть равно 1, потому что нет предыдущей строки для сравнения. так что берите как 60 минут (правило-1). как мы можем это сделать?

akcoban 12.12.2020 18:28

@аккобан . . . COALESCE() должен поступить правильно в этом случае.

Gordon Linoff 12.12.2020 18:55

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