Найдите самое продолжительное время без дождя (каждый час, сверх нескольких дней) - PullRequest
0 голосов
/ 13 июля 2020

У меня есть метеостанция , где я измеряю количество дождя в час и сохраняю данные в базе данных. Таблица дождя выглядит так:

CREATE TABLE `Rain` (
  `id` int(11) NOT NULL,
  `rain` double NOT NULL,
  `date_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `Rain` (`id`, `rain`, `date_time`) VALUES
(1, 0, '2020-07-12 21:00:01'),
(2, 0, '2020-07-12 22:00:01'),
(3, 0, '2020-07-12 23:00:01'),
(4, 0, '2020-07-13 00:00:01'),
(5, 0, '2020-07-13 01:00:01'),
(6, 0, '2020-07-13 02:00:01'),
(7, 0, '2020-07-13 03:00:01');

Теперь мне нужно самое продолжительное время без дождя в месяц. У меня уже есть решение, но оно работает только на соответствующий день. Однако, если в течение нескольких дней не будет дождя, мое решение не будет работать правильно ...

Моя текущая инструкция выглядит так:

SET @row_number:=0;
SELECT rain, date_time, 
        EXTRACT(DAY_HOUR FROM date_time) - @row_number:=@row_number+1 as 'check_sum'
FROM Rain 
WHERE rain=(SELECT MIN(rain) 
            FROM Rain 
            WHERE date_time BETWEEN '2020-07-01 00:00:00' AND '2020-07-31 00:00:00'
            ) 
AND date_time BETWEEN '2020-07-01 00:00:00' AND '2020-07-31 00:00:00'

Результат этого оператора следующий. :

rain date_time           check_sum
   0 2020-07-12 21:00:01      1220
   0 2020-07-12 22:00:02      1220
   0 2020-07-12 23:00:01      1220 
   0 2020-07-13 00:00:01      1296
   0 2020-07-13 01:00:01      1296
   0 2020-07-13 02:00:01      1296
   0 2020-07-13 03:00:01      1296
   0 2020-07-13 04:00:01      1296
   0 2020-07-13 04:00:01      1296

Хотя дождя не было , я получаю другое checksum на следующий день.

SQLFIDDLE

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

day/hour       @row_number+1
(12/21) 1221 -       1       = 1220 same
(12/22) 1222 -       2       = 1220 same
(12/23) 1223 -       3       = 1220 same
(13/00) 1300 -       4       = 1296 not same (day changed)
(13/01) 1301 -       5       = 1296 not same (day changed)
(13/02) 1302 -       6       = 1296 not same (day changed)

Кто-нибудь знает, как это сделать несмотря на смену дня и то же check sum? Или есть другой способ (совершенно новый подход / новый запрос) решить мою проблему?

Заранее спасибо!

Ответы [ 2 ]

1 голос
/ 13 июля 2020

В более старых версиях вы можете использовать переменные:

SELECT MIN(date_time), MAX(date_time),
       TIMESTAMPDIFF(hour, MIN(date_time), MAX(date_time)) hours
FROM (SELECT r.*, (@rn := @rn + 1) as rn
      FROM (SELECT r.*, FLOOR(UNIX_TIMESTAMP(date_time) / 3600) as hh
            FROM Rain r
            WHERE rain = 0
            ORDER BY date_time
           ) r CROSS JOIN
           (SELECT @rn := 0) params
      ) r
GROUP BY (hh - rn)
ORDER BY hours desc

Добавьте LIMIT 1, чтобы получить максимальное количество часов.

Идея состоит в том, чтобы вычислить количество часов (поскольку начало времени) за каждый день без дождя. Если вы вычтите порядковое число из количества часов, вы получите константу для последовательных часов.

Обратите внимание, что этот подход также работает с оконными функциями:

SELECT MIN(date_time), MAX(date_time),
       TIMESTAMPDIFF(hour, MIN(date_time), MAX(date_time)) hours
FROM (SELECT r.*, FLOOR(UNIX_TIMESTAMP(date_time) / 3600) as hh,
             ROW_NUMBER() OVER (ORDER BY date_time) as rn
      FROM Rain r
      WHERE rain = 0
     ) r
GROUP BY (hh - rn)
ORDER BY hours desc
0 голосов
/ 13 июля 2020

Мне это кажется проблемой с промежутками и островками. Я понимаю, что вам нужна самая длинная полоса 0 s в столбце rain.

Если вы используете MySQL 8.0, подход заключается в использовании разницы между номерами строк:

select 
    min(date_time) start_date_time, 
    max(date_time) end_date_time, 
    count(*) no_hours
from (
    select 
        r.*,
        row_number() over(order by date_time) rn1,
        row_number() over(partition by rain order by date_time) rn2
    from rain r
) r
where rain = 0
group by rn1 - rn2
order by no_hours desc
...