Procedure/Function 寻找并填补空白时间点
Procedure/Function to find and fill empty time spots
我有一个名为 DAILY_EVENTS
的 table,它包含这样的数据:
EVENT_ID | EVENT_TYPE | From_date | To_date
-----------+------------+-----+---------------------+---------------------
3 | ACCIDENT | 2013-01-05 01:14:47 | 2013-01-05 01:14:55
6 | TERRORISM | 2013-01-05 22:55:20 | 2013-01-05 22:56:00
8 | NATURAL DISASTER | 2013-01-05 16:05:30 | 2013-01-05 16:05:39
在这些条件下,我需要找到空的时间点来为这一天插入更多行:
a)时间段不能叠加。即新行 From_date 和 To_date 不能在 01:14:47
到 [=15= 之间的范围内],或 22:55:20
到 22:56:00
等等。
b) From_date 时间和 To_date[=48 之间的 10 秒=] 时间即 01:14:00
- 01:14:10
c) 之前插入的事件的 To_date 和 之间至少间隔 2 秒当前事件的 from_date,即如果第一行是 01:14:00
- 01:14:10
,则第二行必须从最小值 01:14:12
开始,并且 To_Date 将是 01:14:22
包含允许数据的 2 个新行(最后一行)的摘要可能是这些:
EVENT_ID | EVENT_TYPE | From_date | To_date
-----------+------------+-----+---------------------+---------------------
3 | ACCIDENT | 2013-01-05 01:14:47 | 2013-01-05 01:14:55
6 | TERRORISM | 2013-01-05 22:55:20 | 2013-01-05 22:56:00
8 | NATURAL DISASTER | 2013-01-05 16:05:30 | 2013-01-05 16:05:39
3 | ACCIDENT | 2013-01-05 00:00:00 | 2013-01-05 00:00:10
6 | ACCIDENT | 2013-01-05 00:00:12 | 2013-01-05 00:00:22
我有点受阻于此要求,我不知道如何开始,知道吗?
您可以使用以下方法生成所有间隙:
SELECT LAG(to_date, 1, TRUNC(from_date)) OVER (ORDER BY From_date) AS gap_start,
from_date AS gap_end
FROM daily_events
WHERE to_date > DATE '2013-01-05'
AND from_date < DATE '2013-01-05' + INTERVAL '1' DAY
UNION ALL
SELECT COALESCE(MAX(to_date), DATE '2013-01-05'),
DATE '2013-01-05' + INTERVAL '1' DAY
FROM daily_events
WHERE to_date > DATE '2013-01-05'
AND from_date < DATE '2013-01-05' + INTERVAL '1' DAY;
其中,对于示例数据:
CREATE TABLE daily_events (EVENT_ID, EVENT_TYPE, From_date, To_date) AS
SELECT 3, 'ACCIDENT', DATE '2013-01-05' + INTERVAL '01:14:47' HOUR TO SECOND, DATE '2013-01-05' + INTERVAL '01:14:55' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 6, 'TERRORISM', DATE '2013-01-05' + INTERVAL '22:55:20' HOUR TO SECOND, DATE '2013-01-05' + INTERVAL '22:56:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 8, 'NATURAL DISASTER', DATE '2013-01-05' + INTERVAL '16:05:30' HOUR TO SECOND, DATE '2013-01-05' + INTERVAL '16:05:39' HOUR TO SECOND FROM DUAL;
输出:
GAP_START
GAP_END
2013-01-05 00:00:00
2013-01-05 01:14:47
2013-01-05 01:14:55
2013-01-05 16:05:30
2013-01-05 16:05:39
2013-01-05 22:55:20
2013-01-05 22:56:00
2013-01-06 00:00:00
然后你只需要在这些间隔内选择一个 10 秒的范围。
您可以生成所有可能的 non-overlapping 10 秒间隔,从上一个间隔结束后 2 秒开始,使用递归查询:
WITH gaps (gap_start, gap_end) AS (
SELECT LAG(to_date, 1, TRUNC(from_date)) OVER (ORDER BY From_date),
from_date
FROM daily_events
WHERE to_date > DATE '2013-01-05'
AND from_date < DATE '2013-01-05' + INTERVAL '1' DAY
UNION ALL
SELECT COALESCE(MAX(to_date), DATE '2013-01-05'),
DATE '2013-01-05' + INTERVAL '1' DAY
FROM daily_events
WHERE to_date > DATE '2013-01-05'
AND from_date < DATE '2013-01-05' + INTERVAL '1' DAY
),
intervals (gap_start, gap_end, int_start, int_end) AS (
SELECT gap_start,
gap_end,
gap_start + INTERVAL '2' SECOND,
gap_start + INTERVAL '12' SECOND
FROM gaps
WHERE gap_start + INTERVAL '14' SECOND <= gap_end
UNION ALL
SELECT gap_start,
gap_end,
int_end + INTERVAL '2' SECOND,
int_end + INTERVAL '12' SECOND
FROM intervals
WHERE int_end + INTERVAL '14' SECOND <= gap_end
)
SEARCH DEPTH FIRST BY gap_start SET int_order
SELECT int_start, int_end
FROM intervals;
其中,对于示例数据,输出:
INT_START
INT_END
2013-01-05 00:00:02
2013-01-05 00:00:12
2013-01-05 00:00:14
2013-01-05 00:00:24
2013-01-05 00:00:26
2013-01-05 00:00:36
...
...
2013-01-05 01:14:02
2013-01-05 01:14:12
2013-01-05 01:14:14
2013-01-05 01:14:24
2013-01-05 01:14:26
2013-01-05 01:14:36
2013-01-05 01:14:57
2013-01-05 01:15:07
2013-01-05 01:15:09
2013-01-05 01:15:19
2013-01-05 01:15:21
2013-01-05 01:15:31
...
...
2013-01-05 16:04:45
2013-01-05 16:04:55
2013-01-05 16:04:57
2013-01-05 16:05:07
2013-01-05 16:05:09
2013-01-05 16:05:19
2013-01-05 16:05:41
2013-01-05 16:05:51
2013-01-05 16:05:53
2013-01-05 16:06:03
2013-01-05 16:06:05
2013-01-05 16:06:15
...
...
2013-01-05 22:56:26
2013-01-05 22:56:36
2013-01-05 22:56:38
2013-01-05 22:56:48
2013-01-05 22:56:50
2013-01-05 22:57:00
2013-01-05 22:57:02
2013-01-05 22:57:12
2013-01-05 22:57:14
2013-01-05 22:57:24
2013-01-05 22:57:26
2013-01-05 22:57:36
...
...
2013-01-05 23:59:14
2013-01-05 23:59:24
2013-01-05 23:59:26
2013-01-05 23:59:36
2013-01-05 23:59:38
2013-01-05 23:59:48
db<>fiddle here
我有一个名为 DAILY_EVENTS
的 table,它包含这样的数据:
EVENT_ID | EVENT_TYPE | From_date | To_date
-----------+------------+-----+---------------------+---------------------
3 | ACCIDENT | 2013-01-05 01:14:47 | 2013-01-05 01:14:55
6 | TERRORISM | 2013-01-05 22:55:20 | 2013-01-05 22:56:00
8 | NATURAL DISASTER | 2013-01-05 16:05:30 | 2013-01-05 16:05:39
在这些条件下,我需要找到空的时间点来为这一天插入更多行:
a)时间段不能叠加。即新行 From_date 和 To_date 不能在 01:14:47
到 [=15= 之间的范围内],或 22:55:20
到 22:56:00
等等。
b) From_date 时间和 To_date[=48 之间的 10 秒=] 时间即 01:14:00
- 01:14:10
c) 之前插入的事件的 To_date 和 之间至少间隔 2 秒当前事件的 from_date,即如果第一行是 01:14:00
- 01:14:10
,则第二行必须从最小值 01:14:12
开始,并且 To_Date 将是 01:14:22
包含允许数据的 2 个新行(最后一行)的摘要可能是这些:
EVENT_ID | EVENT_TYPE | From_date | To_date
-----------+------------+-----+---------------------+---------------------
3 | ACCIDENT | 2013-01-05 01:14:47 | 2013-01-05 01:14:55
6 | TERRORISM | 2013-01-05 22:55:20 | 2013-01-05 22:56:00
8 | NATURAL DISASTER | 2013-01-05 16:05:30 | 2013-01-05 16:05:39
3 | ACCIDENT | 2013-01-05 00:00:00 | 2013-01-05 00:00:10
6 | ACCIDENT | 2013-01-05 00:00:12 | 2013-01-05 00:00:22
我有点受阻于此要求,我不知道如何开始,知道吗?
您可以使用以下方法生成所有间隙:
SELECT LAG(to_date, 1, TRUNC(from_date)) OVER (ORDER BY From_date) AS gap_start,
from_date AS gap_end
FROM daily_events
WHERE to_date > DATE '2013-01-05'
AND from_date < DATE '2013-01-05' + INTERVAL '1' DAY
UNION ALL
SELECT COALESCE(MAX(to_date), DATE '2013-01-05'),
DATE '2013-01-05' + INTERVAL '1' DAY
FROM daily_events
WHERE to_date > DATE '2013-01-05'
AND from_date < DATE '2013-01-05' + INTERVAL '1' DAY;
其中,对于示例数据:
CREATE TABLE daily_events (EVENT_ID, EVENT_TYPE, From_date, To_date) AS
SELECT 3, 'ACCIDENT', DATE '2013-01-05' + INTERVAL '01:14:47' HOUR TO SECOND, DATE '2013-01-05' + INTERVAL '01:14:55' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 6, 'TERRORISM', DATE '2013-01-05' + INTERVAL '22:55:20' HOUR TO SECOND, DATE '2013-01-05' + INTERVAL '22:56:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 8, 'NATURAL DISASTER', DATE '2013-01-05' + INTERVAL '16:05:30' HOUR TO SECOND, DATE '2013-01-05' + INTERVAL '16:05:39' HOUR TO SECOND FROM DUAL;
输出:
GAP_START GAP_END 2013-01-05 00:00:00 2013-01-05 01:14:47 2013-01-05 01:14:55 2013-01-05 16:05:30 2013-01-05 16:05:39 2013-01-05 22:55:20 2013-01-05 22:56:00 2013-01-06 00:00:00
然后你只需要在这些间隔内选择一个 10 秒的范围。
您可以生成所有可能的 non-overlapping 10 秒间隔,从上一个间隔结束后 2 秒开始,使用递归查询:
WITH gaps (gap_start, gap_end) AS (
SELECT LAG(to_date, 1, TRUNC(from_date)) OVER (ORDER BY From_date),
from_date
FROM daily_events
WHERE to_date > DATE '2013-01-05'
AND from_date < DATE '2013-01-05' + INTERVAL '1' DAY
UNION ALL
SELECT COALESCE(MAX(to_date), DATE '2013-01-05'),
DATE '2013-01-05' + INTERVAL '1' DAY
FROM daily_events
WHERE to_date > DATE '2013-01-05'
AND from_date < DATE '2013-01-05' + INTERVAL '1' DAY
),
intervals (gap_start, gap_end, int_start, int_end) AS (
SELECT gap_start,
gap_end,
gap_start + INTERVAL '2' SECOND,
gap_start + INTERVAL '12' SECOND
FROM gaps
WHERE gap_start + INTERVAL '14' SECOND <= gap_end
UNION ALL
SELECT gap_start,
gap_end,
int_end + INTERVAL '2' SECOND,
int_end + INTERVAL '12' SECOND
FROM intervals
WHERE int_end + INTERVAL '14' SECOND <= gap_end
)
SEARCH DEPTH FIRST BY gap_start SET int_order
SELECT int_start, int_end
FROM intervals;
其中,对于示例数据,输出:
INT_START INT_END 2013-01-05 00:00:02 2013-01-05 00:00:12 2013-01-05 00:00:14 2013-01-05 00:00:24 2013-01-05 00:00:26 2013-01-05 00:00:36 ... ... 2013-01-05 01:14:02 2013-01-05 01:14:12 2013-01-05 01:14:14 2013-01-05 01:14:24 2013-01-05 01:14:26 2013-01-05 01:14:36 2013-01-05 01:14:57 2013-01-05 01:15:07 2013-01-05 01:15:09 2013-01-05 01:15:19 2013-01-05 01:15:21 2013-01-05 01:15:31 ... ... 2013-01-05 16:04:45 2013-01-05 16:04:55 2013-01-05 16:04:57 2013-01-05 16:05:07 2013-01-05 16:05:09 2013-01-05 16:05:19 2013-01-05 16:05:41 2013-01-05 16:05:51 2013-01-05 16:05:53 2013-01-05 16:06:03 2013-01-05 16:06:05 2013-01-05 16:06:15 ... ... 2013-01-05 22:56:26 2013-01-05 22:56:36 2013-01-05 22:56:38 2013-01-05 22:56:48 2013-01-05 22:56:50 2013-01-05 22:57:00 2013-01-05 22:57:02 2013-01-05 22:57:12 2013-01-05 22:57:14 2013-01-05 22:57:24 2013-01-05 22:57:26 2013-01-05 22:57:36 ... ... 2013-01-05 23:59:14 2013-01-05 23:59:24 2013-01-05 23:59:26 2013-01-05 23:59:36 2013-01-05 23:59:38 2013-01-05 23:59:48
db<>fiddle here