每 table 行创建 n 分钟间隔
Creating n minute intervals per table row
我正在尝试根据 table.
获取时间间隔
我的来源 table 是这样的:
ID
OTHER_DATA
TIME_BEG
TIME_END
DURATION
1
abcd
10:00
11:00
15
2
xyzt
16:00
17:00
30
期望的输出:
ID
OTHER_DATA
ITVL_BEG
ITVL_END
1
abcd
10:00
10:15
1
abcd
10:15
10:30
1
abcd
10:30
10:45
1
abcd
10:45
11:00
2
xyzt
16:00
16:30
2
xyzt
16:30
17:00
TIME_BEG
和 TIME_END
是 VARCHAR
列,但我也将它们设为 DAY TO SECOND INTERVAL
,此处未显示(TIME_BEG_INT 和 TIME_END_INT)。
基本上我需要将每一行复制 TRUNC (EXTRACT (DAY FROM 24 * 60 * (TIME_END_INT - TIME_BEG_INT)) / DURATION)
次并将这个*DURATION 添加到我的日期中,一次 SQL.
感谢任何帮助。
如果您使用间隔:
CREATE TABLE table_name (ID, OTHER_DATA, TIME_BEG, TIME_END, DURATION) AS
SELECT 1, 'abcd', INTERVAL '10:00' HOUR TO MINUTE, INTERVAL '11:00' HOUR TO MINUTE, INTERVAL '15' MINUTE FROM DUAL UNION ALL
SELECT 2, 'xyzt', INTERVAL '16:00' HOUR TO MINUTE, INTERVAL '17:00' HOUR TO MINUTE, INTERVAL '30' MINUTE FROM DUAL;
那么你可以使用:
WITH range (ID, OTHER_DATA, TIME_BEG, TIME_INT_END, TIME_END, DURATION) AS (
SELECT ID,
OTHER_DATA,
TIME_BEG,
LEAST(time_beg + duration, time_end),
TIME_END,
DURATION
FROM table_name
UNION ALL
SELECT ID,
OTHER_DATA,
TIME_INT_END,
LEAST(time_int_end + duration, time_end),
TIME_END,
DURATION
FROM range
WHERE time_int_end < time_end
)
SEARCH DEPTH FIRST BY id SET id_order
SELECT ID,
OTHER_DATA,
TIME_BEG AS itvl_beg,
TIME_INT_END AS itvl_end
FROM range;
输出:
ID
OTHER_DATA
ITVL_BEG
ITVL_END
1
abcd
+000000000 10:00:00.000000000
+000000000 10:15:00.000000000
1
abcd
+000000000 10:15:00.000000000
+000000000 10:30:00.000000000
1
abcd
+000000000 10:30:00.000000000
+000000000 10:45:00.000000000
1
abcd
+000000000 10:45:00.000000000
+000000000 11:00:00.000000000
2
xyzt
+000000000 16:00:00.000000000
+000000000 16:30:00.000000000
2
xyzt
+000000000 16:30:00.000000000
+000000000 17:00:00.000000000
如果您的值是字符串,那么您可以先将它们转换为区间:
CREATE TABLE table_name (ID, OTHER_DATA, TIME_BEG, TIME_END, DURATION) AS
SELECT 1, 'abcd', '10:00', '11:00', 15 FROM DUAL UNION ALL
SELECT 2, 'xyzt', '16:00', '17:00', 30 FROM DUAL;
WITH data(ID, OTHER_DATA, TIME_BEG, TIME_END, DURATION) AS (
SELECT ID,
OTHER_DATA,
TO_DSINTERVAL('0 '||TIME_BEG||':00'),
TO_DSINTERVAL('0 '||TIME_END||':00'),
NUMTODSINTERVAL(DURATION, 'MINUTE')
FROM table_name
),
range (ID, OTHER_DATA, TIME_BEG, TIME_INT_END, TIME_END, DURATION) AS (
SELECT ID,
OTHER_DATA,
TIME_BEG,
LEAST(time_beg + duration, time_end),
TIME_END,
DURATION
FROM data
UNION ALL
SELECT ID,
OTHER_DATA,
TIME_INT_END,
LEAST(time_int_end + duration, time_end),
TIME_END,
DURATION
FROM range
WHERE time_int_end < time_end
)
SEARCH DEPTH FIRST BY id SET id_order
SELECT ID,
OTHER_DATA,
TIME_BEG AS itvl_beg,
TIME_INT_END AS itvl_end
FROM range;
db<>fiddle here
这是基于预间隔DATE
计算
的经典解决方案
with time_int(ID, OTHER_DATA, ITVL_BEG, ITVL_END, DURATION, TIME_END) as (
select
ID, OTHER_DATA, TIME_BEG,
to_char(to_date(time_beg,'HH24:mi')+duration/(24*60),'HH24:mi'),
DURATION, TIME_END
from tab
union all
select
ID, OTHER_DATA, ITVL_END,
to_char(to_date(ITVL_END,'HH24:mi')+duration/(24*60),'HH24:mi'),
DURATION, TIME_END
from time_int
where ITVL_END <= TIME_END
)
select
ID, OTHER_DATA, ITVL_BEG, ITVL_END
from time_int
order by 1,3;
ID OTHE ITVL_ ITVL_
---------- ---- ----- -----
1 abcd 10:00 10:15
1 abcd 10:15 10:30
1 abcd 10:30 10:45
1 abcd 10:45 11:00
1 abcd 11:00 11:15
2 xyzt 16:00 16:30
2 xyzt 16:30 17:00
2 xyzt 17:00 17:30
一个recursive CTE与step一起使用,根据下面的计算得到下一个区间边界(假设你的时间是存储为 VARCHAR2)
to_char(to_date(time_beg,'HH24:mi')+duration/(24*60),'HH24:mi')
请注意,您可以将 10:00
转换为 日期 并且 Oracle 提供了默认缺失的日、月和年,您不需要这些,因为在增加 duration
你转换回 HH24:MI
字符串。
我正在尝试根据 table.
获取时间间隔我的来源 table 是这样的:
ID | OTHER_DATA | TIME_BEG | TIME_END | DURATION |
---|---|---|---|---|
1 | abcd | 10:00 | 11:00 | 15 |
2 | xyzt | 16:00 | 17:00 | 30 |
期望的输出:
ID | OTHER_DATA | ITVL_BEG | ITVL_END |
---|---|---|---|
1 | abcd | 10:00 | 10:15 |
1 | abcd | 10:15 | 10:30 |
1 | abcd | 10:30 | 10:45 |
1 | abcd | 10:45 | 11:00 |
2 | xyzt | 16:00 | 16:30 |
2 | xyzt | 16:30 | 17:00 |
TIME_BEG
和 TIME_END
是 VARCHAR
列,但我也将它们设为 DAY TO SECOND INTERVAL
,此处未显示(TIME_BEG_INT 和 TIME_END_INT)。
基本上我需要将每一行复制 TRUNC (EXTRACT (DAY FROM 24 * 60 * (TIME_END_INT - TIME_BEG_INT)) / DURATION)
次并将这个*DURATION 添加到我的日期中,一次 SQL.
感谢任何帮助。
如果您使用间隔:
CREATE TABLE table_name (ID, OTHER_DATA, TIME_BEG, TIME_END, DURATION) AS
SELECT 1, 'abcd', INTERVAL '10:00' HOUR TO MINUTE, INTERVAL '11:00' HOUR TO MINUTE, INTERVAL '15' MINUTE FROM DUAL UNION ALL
SELECT 2, 'xyzt', INTERVAL '16:00' HOUR TO MINUTE, INTERVAL '17:00' HOUR TO MINUTE, INTERVAL '30' MINUTE FROM DUAL;
那么你可以使用:
WITH range (ID, OTHER_DATA, TIME_BEG, TIME_INT_END, TIME_END, DURATION) AS (
SELECT ID,
OTHER_DATA,
TIME_BEG,
LEAST(time_beg + duration, time_end),
TIME_END,
DURATION
FROM table_name
UNION ALL
SELECT ID,
OTHER_DATA,
TIME_INT_END,
LEAST(time_int_end + duration, time_end),
TIME_END,
DURATION
FROM range
WHERE time_int_end < time_end
)
SEARCH DEPTH FIRST BY id SET id_order
SELECT ID,
OTHER_DATA,
TIME_BEG AS itvl_beg,
TIME_INT_END AS itvl_end
FROM range;
输出:
ID OTHER_DATA ITVL_BEG ITVL_END 1 abcd +000000000 10:00:00.000000000 +000000000 10:15:00.000000000 1 abcd +000000000 10:15:00.000000000 +000000000 10:30:00.000000000 1 abcd +000000000 10:30:00.000000000 +000000000 10:45:00.000000000 1 abcd +000000000 10:45:00.000000000 +000000000 11:00:00.000000000 2 xyzt +000000000 16:00:00.000000000 +000000000 16:30:00.000000000 2 xyzt +000000000 16:30:00.000000000 +000000000 17:00:00.000000000
如果您的值是字符串,那么您可以先将它们转换为区间:
CREATE TABLE table_name (ID, OTHER_DATA, TIME_BEG, TIME_END, DURATION) AS
SELECT 1, 'abcd', '10:00', '11:00', 15 FROM DUAL UNION ALL
SELECT 2, 'xyzt', '16:00', '17:00', 30 FROM DUAL;
WITH data(ID, OTHER_DATA, TIME_BEG, TIME_END, DURATION) AS (
SELECT ID,
OTHER_DATA,
TO_DSINTERVAL('0 '||TIME_BEG||':00'),
TO_DSINTERVAL('0 '||TIME_END||':00'),
NUMTODSINTERVAL(DURATION, 'MINUTE')
FROM table_name
),
range (ID, OTHER_DATA, TIME_BEG, TIME_INT_END, TIME_END, DURATION) AS (
SELECT ID,
OTHER_DATA,
TIME_BEG,
LEAST(time_beg + duration, time_end),
TIME_END,
DURATION
FROM data
UNION ALL
SELECT ID,
OTHER_DATA,
TIME_INT_END,
LEAST(time_int_end + duration, time_end),
TIME_END,
DURATION
FROM range
WHERE time_int_end < time_end
)
SEARCH DEPTH FIRST BY id SET id_order
SELECT ID,
OTHER_DATA,
TIME_BEG AS itvl_beg,
TIME_INT_END AS itvl_end
FROM range;
db<>fiddle here
这是基于预间隔DATE
计算
with time_int(ID, OTHER_DATA, ITVL_BEG, ITVL_END, DURATION, TIME_END) as (
select
ID, OTHER_DATA, TIME_BEG,
to_char(to_date(time_beg,'HH24:mi')+duration/(24*60),'HH24:mi'),
DURATION, TIME_END
from tab
union all
select
ID, OTHER_DATA, ITVL_END,
to_char(to_date(ITVL_END,'HH24:mi')+duration/(24*60),'HH24:mi'),
DURATION, TIME_END
from time_int
where ITVL_END <= TIME_END
)
select
ID, OTHER_DATA, ITVL_BEG, ITVL_END
from time_int
order by 1,3;
ID OTHE ITVL_ ITVL_
---------- ---- ----- -----
1 abcd 10:00 10:15
1 abcd 10:15 10:30
1 abcd 10:30 10:45
1 abcd 10:45 11:00
1 abcd 11:00 11:15
2 xyzt 16:00 16:30
2 xyzt 16:30 17:00
2 xyzt 17:00 17:30
一个recursive CTE与step一起使用,根据下面的计算得到下一个区间边界(假设你的时间是存储为 VARCHAR2)
to_char(to_date(time_beg,'HH24:mi')+duration/(24*60),'HH24:mi')
请注意,您可以将 10:00
转换为 日期 并且 Oracle 提供了默认缺失的日、月和年,您不需要这些,因为在增加 duration
你转换回 HH24:MI
字符串。