您需要几个步骤。首先,对于每条记录,您需要查看它有多少小时的连续先前数据。这就是grouped_hour_data 子句在下面的解决方案中所做的。
然后,您需要从该结果中进行选择,仅获取具有完整 24 小时连续先前数据的行。然后只获取前 24 行。
此解决方案经过简化,以利用您的所有日期都被截断为小时并且没有重复的事实。如果您的问题比这更复杂,这个解决方案仍然可以支持它,但需要对其进行修改。
在此示例中,我们创建了几天前的测试数据,但从 16 日和 17 日的各个小时删除数据,以便第一个连续 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 |
+----------------------+-----+
编辑:处理类别字段
要处理您添加的额外 category 字段,您需要做一些事情。
首先,PARTITION BY category 在计算 cnt 字段时。这将导致在计算此值时分别处理每个类别的数据。因此,例如,A 类在第 2 小时的值不会算作 B 类在第 2 小时的值。
其次,你不能再使用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;
披露:我没有测试这个更新的逻辑,所以可能会有一些错误。