我有两次定义时间范围的数据。
CREATE TABLE MY_TIME_TABLE
(
MY_PK NUMBER(10) NOT NULL ENABLE,
FROM_TIME DATE NOT NULL ENABLE,
TO_TIME DATE NOT NULL ENABLE
);
INSERT INTO MY_TIME_TABLE(MY_PK,FROM_TIME,TO_TIME)
VALUES(1,TO_DATE('2014-01-01 09:00:00', 'YYYY-MM-DD HH24:MI:SS'),TO_DATE('2014-01-01 13:00:00', 'YYYY-MM-DD HH24:MI:SS');
INSERT INTO MY_TIME_TABLE(MY_PK,FROM_TIME,TO_TIME)
VALUES(2,TO_DATE('2014-01-02 14:00:00', 'YYYY-MM-DD HH24:MI:SS'),TO_DATE('2014-01-02 15:00:00', 'YYYY-MM-DD HH24:MI:SS');
INSERT INTO MY_TIME_TABLEMY_PK,(FROM_TIME,TO_TIME)
VALUES(3,TO_DATE('2014-01-03 00:30:00', 'YYYY-MM-DD HH24:MI:SS'),TO_DATE('2014-01-03 03:30:00', 'YYYY-MM-DD HH24:MI:SS');
我想要做的是创建一个查询,该查询将返回两次中的每一个之间的所有半小时块。所以它会返回如下内容:
1, 2014-01-01 09:00:00
1, 2014-01-01 09:30:00
1, 2014-01-01 10:00:00
1, 2014-01-01 10:30:00
1, 2014-01-01 11:00:00
1, 2014-01-01 11:30:00
1, 2014-01-01 12:00:00
1, 2014-01-01 12:30:00
2, 2014-01-02 14:00:00
2, 2014-01-02 14:30:00
3, 2014-01-03 00:30:00
3, 2014-01-03 01:00:00
3, 2014-01-03 01:30:00
3, 2014-01-03 02:00:00
3, 2014-01-03 02:30:00
3, 2014-01-03 03:00:00
保证数据在小时或半小时开始和结束,所以我不必担心部分匹配。
我通常会尝试展示我自己完成的工作来解决我的问题,但在这种情况下,我甚至没有最微弱的线索从哪里开始。
答案 0 :(得分:4)
您可以使用分层查询或CTE来执行此操作。
Oracle 11g R2架构设置:
CREATE TABLE MY_TIME_TABLE ( MY_PK, FROM_TIME, TO_TIME ) AS
SELECT 1, TO_DATE('2014-01-01 09:00:00', 'YYYY-MM-DD HH24:MI:SS'), TO_DATE('2014-01-01 13:00:00', 'YYYY-MM-DD HH24:MI:SS') FROM DUAL
UNION ALL
SELECT 2, TO_DATE('2014-01-02 14:00:00', 'YYYY-MM-DD HH24:MI:SS'), TO_DATE('2014-01-02 15:00:00', 'YYYY-MM-DD HH24:MI:SS') FROM DUAL
UNION ALL
SELECT 3, TO_DATE('2014-01-03 00:30:00', 'YYYY-MM-DD HH24:MI:SS'), TO_DATE('2014-01-03 03:30:00', 'YYYY-MM-DD HH24:MI:SS') FROM DUAL;
分层查询:
SELECT MY_PK, FROM_TIME + (LEVEL-1) / 48
FROM MY_TIME_TABLE
CONNECT BY LEVEL <= (TO_TIME - FROM_TIME) * 48
AND PRIOR MY_PK = MY_PK
AND PRIOR dbms_random.value IS NOT NULL
<强> Results 强>:
| MY_PK | FROM_TIME+(LEVEL-1)/48 |
|-------|--------------------------------|
| 1 | January, 01 2014 09:00:00+0000 |
| 1 | January, 01 2014 09:30:00+0000 |
| 1 | January, 01 2014 10:00:00+0000 |
| 1 | January, 01 2014 10:30:00+0000 |
| 1 | January, 01 2014 11:00:00+0000 |
| 1 | January, 01 2014 11:30:00+0000 |
| 1 | January, 01 2014 12:00:00+0000 |
| 1 | January, 01 2014 12:30:00+0000 |
| 2 | January, 02 2014 14:00:00+0000 |
| 2 | January, 02 2014 14:30:00+0000 |
| 3 | January, 03 2014 00:30:00+0000 |
| 3 | January, 03 2014 01:00:00+0000 |
| 3 | January, 03 2014 01:30:00+0000 |
| 3 | January, 03 2014 02:00:00+0000 |
| 3 | January, 03 2014 02:30:00+0000 |
| 3 | January, 03 2014 03:00:00+0000 |
答案 1 :(得分:3)
如果你正在使用11gR2,你可以使用recursive subquery factoring(也就是递归CTE或递归):
with r (my_pk, from_time, to_time) as (
select my_pk, from_time, to_time
from my_time_table
union all
select my_pk, from_time + interval '30' minute, to_time
from r
where from_time + interval '30' minute < to_time
)
select my_pk, to_char(from_time, 'YYYY-MM-DD HH24:MI:SS') as from_time
from r
order by my_pk, from_time;
MY_PK FROM_TIME
---------- -------------------
1 2014-01-01 09:00:00
1 2014-01-01 09:30:00
1 2014-01-01 10:00:00
1 2014-01-01 10:30:00
1 2014-01-01 11:00:00
1 2014-01-01 11:30:00
1 2014-01-01 12:00:00
1 2014-01-01 12:30:00
2 2014-01-02 14:00:00
2 2014-01-02 14:30:00
3 2014-01-03 00:30:00
3 2014-01-03 01:00:00
3 2014-01-03 01:30:00
3 2014-01-03 02:00:00
3 2014-01-03 02:30:00
3 2014-01-03 03:00:00
anchor子句获取每个PK值的开始时间,并且递归部分持续添加30分钟的间隔,直到达到该PK的结束时间。然后,您可以将该CTE用作查询中其他位置的源表;在这里,我只是清楚地展示内容。
根据您将如何使用这些范围,您可能会发现生成每个半小时块的结尾也很有用,例如:用于主查询中的between
子句:
with r (my_pk, from_time, to_time, max_time) as (
select my_pk, from_time,
from_time + interval '30' minute - interval '1' second, to_time
from my_time_table
union all
select my_pk, from_time + interval '30' minute,
to_time + interval '30' minute, max_time
from r
where from_time + interval '30' minute < max_time
)
select my_pk, to_char(from_time, 'YYYY-MM-DD HH24:MI:SS') as from_time,
to_char(to_time, 'YYYY-MM-DD HH24:MI:SS') as to_time
from r
order by my_pk, from_time;
MY_PK FROM_TIME TO_TIME
---------- ------------------- -------------------
1 2014-01-01 09:00:00 2014-01-01 09:29:59
1 2014-01-01 09:30:00 2014-01-01 09:59:59
1 2014-01-01 10:00:00 2014-01-01 10:29:59
1 2014-01-01 10:30:00 2014-01-01 10:59:59
1 2014-01-01 11:00:00 2014-01-01 11:29:59
1 2014-01-01 11:30:00 2014-01-01 11:59:59
1 2014-01-01 12:00:00 2014-01-01 12:29:59
1 2014-01-01 12:30:00 2014-01-01 12:59:59
2 2014-01-02 14:00:00 2014-01-02 14:29:59
2 2014-01-02 14:30:00 2014-01-02 14:59:59
3 2014-01-03 00:30:00 2014-01-03 00:59:59
3 2014-01-03 01:00:00 2014-01-03 01:29:59
3 2014-01-03 01:30:00 2014-01-03 01:59:59
3 2014-01-03 02:00:00 2014-01-03 02:29:59
3 2014-01-03 02:30:00 2014-01-03 02:59:59
3 2014-01-03 03:00:00 2014-01-03 03:29:59
答案 2 :(得分:2)
select my_pk, from_time + (half_hour_increment-1) * interval '30' minute new_time
from
(
select my_pk, from_time, to_time, (to_time-from_time)*24*2 half_hours
from my_time_table
) my_time_table
join
(
select level half_hour_increment
from
(
select max(to_time-from_time)*24*2 max_half_hours
from my_time_table
)
connect by level <= max_half_hours
) row_generator
on half_hours >= half_hour_increment
order by my_pk, half_hour_increment;