Вам нужно несколько шагов. Во-первых, для каждой записи вам нужно увидеть, сколько часов непрерывных предшествующих данных у нее есть. Это то, что делает предложение grouped_hour_data
в приведенном ниже решении.
Затем вам нужно выбрать из этого результата, получая только строки, которые имеют полные 24 часа непрерывных предшествующих данных. Затем выберите только первые 24 строки из этого.
Это решение упрощено, чтобы воспользоваться тем фактом, что все ваши даты были усечены до часа и не было дубликатов. Если ваша проблема более сложная, это решение все еще может поддерживать ее, но ее необходимо будет пересмотреть.
В этом примере мы создаем тестовые данные за несколько дней, но удаляем данные за отдельные часы на 16-е и 17-е, так что 1-й непрерывный 24-часовой период заканчивается раньше 16-го числа.
alter session set nls_date_format = 'DD-MON-YYYY HH24:MI:SS';
with hour_data_raw AS (
SELECT to_date('17-JUN-2020 17:00:00','DD-MON-YYYY HH24:MI:SS') - ( INTERVAL '1' HOUR ) * rownum dte
FROM dual
CONNECT BY rownum <= 200 ),
hour_data AS ( SELECT dte
FROM hour_data_raw
WHERE NOT TRUNC(dte,'HH') = to_date('17-JUN-2020 02:00:00','DD-MON-YYYY HH24:MI:SS')
AND NOT TRUNC(dte,'HH') = to_date('16-JUN-2020 02:00:00','DD-MON-YYYY HH24:MI:SS') ),
-- SOLUTION BEGINS HERE... everything above is just test data
-- WITH...
grouped_hour_data AS (
SELECT h.*, count(trunc(h.dte,'HH')) OVER ( ORDER BY dte desc RANGE BETWEEN CURRENT ROW AND INTERVAL '1' DAY - INTERVAL '1' SECOND FOLLOWING ) cnt
FROM hour_data h
ORDER BY dte)
SELECT * FROM grouped_hour_data
WHERE cnt = 24
ORDER BY dte desc
FETCH FIRST 24 ROWS ONLY;
+----------------------+-----+
| DTE | CNT |
+----------------------+-----+
| 16-JUN-2020 01:00:00 | 24 |
| 16-JUN-2020 00:00:00 | 24 |
| 15-JUN-2020 23:00:00 | 24 |
| 15-JUN-2020 22:00:00 | 24 |
| 15-JUN-2020 21:00:00 | 24 |
| 15-JUN-2020 20:00:00 | 24 |
| 15-JUN-2020 19:00:00 | 24 |
| 15-JUN-2020 18:00:00 | 24 |
| 15-JUN-2020 17:00:00 | 24 |
| 15-JUN-2020 16:00:00 | 24 |
| 15-JUN-2020 15:00:00 | 24 |
| 15-JUN-2020 14:00:00 | 24 |
| 15-JUN-2020 13:00:00 | 24 |
| 15-JUN-2020 12:00:00 | 24 |
| 15-JUN-2020 11:00:00 | 24 |
| 15-JUN-2020 10:00:00 | 24 |
| 15-JUN-2020 09:00:00 | 24 |
| 15-JUN-2020 08:00:00 | 24 |
| 15-JUN-2020 07:00:00 | 24 |
| 15-JUN-2020 06:00:00 | 24 |
| 15-JUN-2020 05:00:00 | 24 |
| 15-JUN-2020 04:00:00 | 24 |
| 15-JUN-2020 03:00:00 | 24 |
| 15-JUN-2020 02:00:00 | 24 |
+----------------------+-----+
EDIT: обработка поля категории
Для обработки дополнительное поле category
, которое вы добавили, вам нужно сделать несколько вещей.
Во-первых, PARTITION BY category
при вычислении поля cnt
. Это приведет к тому, что данные каждой категории будут обрабатываться отдельно при вычислении этого значения. Так, например, значение часа 2 для категории A не будет считаться значением часа 2 для категории B.
Во-вторых, вы больше не можете использовать FETCH FIRST 24 ROWS ONLY
для получения желаемых данных, потому что вам нужны первые 24 строки в каждой категории. Итак, вам нужен дополнительный шаг (ordered_groups
, в пересмотренном ниже запросе), чтобы упорядочить строки в каждой категории, которым предшествуют 24 часа непрерывных данных. Назовите этот заказ rn
, а затем в последнем запросе просто выберите where rn <= 24
.
WITH grouped_hour_data AS (
SELECT h.*, count(trunc(h.dte,'HH')) OVER (
PARTITION BY category
ORDER BY dte desc
RANGE BETWEEN CURRENT ROW
AND INTERVAL '1' DAY - INTERVAL '1' SECOND FOLLOWING ) cnt
FROM hour_data h
ORDER BY dte),
ordered_groups AS (
SELECT ghd.*, row_number() over ( partition by ghd.category order by ghd.dte desc ) rn
FROM grouped_hour_data
WHERE ghd.cnt = 24 )
SELECT * FROM ordered_groups
WHERE rn <= 24;
ORDER BY category, dte desc;
Раскрытие информации: я не тестировал этот обновленный logi c, поэтому могут быть некоторые ошибки.