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_dateTo_date 不能在 01:14:47 到 [=15= 之间的范围内],或 22:55:2022: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