我有一堆日期范围存储在表格的记录中,其中许多重叠。
2013-03-10 10:00 - 2013-03-10 16:00
2013-03-10 15:00 - 2013-03-10 17:00
2013-03-10 20:00 - 2013-03-10 22:00
对于我的光标我有两个输入日期,我需要知道这两个日期之间的时间是由上表中存储的范围所涵盖的。
对于此范围:
2013-03-10 12:00 - 2013-03-10 23:00
上述范围涵盖7小时
希望这很清楚。
通常情况下,我会发布我尝试过的内容,但我似乎根本无法将其与SQL查询纠缠在一起。我所拥有的最好的是来自我的光标内的PLSQL函数调用,它循环遍历其他几个游标,试图将表中的日期范围混合在一起,然后从给定范围中减去它,这是一个可怕的混乱。
我目前正在使用Oracle 10g,但我们目前正在迁移到11g,因此在迁移完成之前,我无法使用任何特定于任何版本的内容。
答案 0 :(得分:3)
架构:
create table Overlapping_Ranges (B date, E date);
insert into Overlapping_Ranges (B, E) values
(to_date('2013-03-10 10:00', 'yyyy-mm-dd hh24:mi'), to_date('2013-03-10 16:00', 'yyyy-mm-dd hh24:mi'));
insert into Overlapping_Ranges (B, E) values
(to_date('2013-03-10 15:00', 'yyyy-mm-dd hh24:mi'), to_date('2013-03-10 17:00', 'yyyy-mm-dd hh24:mi'));
insert into Overlapping_Ranges (B, E) values
(to_date('2013-03-10 20:00', 'yyyy-mm-dd hh24:mi'), to_date('2013-03-10 22:00', 'yyyy-mm-dd hh24:mi'));
create table Ranges_from_cursor (B date, E date);
insert into Ranges_from_cursor (B, E) values
(to_date('2013-03-10 12:00', 'yyyy-mm-dd hh24:mi'), to_date('2013-03-10 23:00', 'yyyy-mm-dd hh24:mi'));
选择:
select
to_char(c.B, 'yyyy-mm-dd hh24:mi') as "From",
to_char(c.E, 'yyyy-mm-dd hh24:mi') as "To",
sum(greatest(0, least(r.E, c.E) - greatest(r.B, c.B))) * 24 as "Hours Overlapped"
from
Ranges_from_cursor c,
(
select distinct
r.B, r.E
from
(
select
T as B,
lead(T) over (order by T) as E,
T + (lead(T) over (order by T) - T)/2 as M
from
(
select B as T from Overlapping_Ranges
union
select E as T from Overlapping_Ranges
)
) r
join Overlapping_Ranges o
on r.M between o.B and o.E
)r
group by c.B, c.E
order by 1
输出:
FROM TO HOURS OVERLAPPED
2013-03-10 12:00 2013-03-10 23:00 7
答案 1 :(得分:1)
这就是你要找的东西吗?
SELECT MIND1,
MAXD2,
24*(MAXD2-MIND1)
FROM
(SELECT MIN(d1) MIND1,
MAX(d2)MAXD2
FROM my_test1
WHERE D1>'10-mar-2013 12:00:00'
AND d2 < '10-mar-2013 23:00:00'
);
请参阅fiddle此处
答案 2 :(得分:0)
这对我来说非常适合。
WITH daterange AS (
SELECT TO_DATE('2013-03-10 10:00', 'YYYY:MM:DD HH24:MI') AS date_from, TO_DATE('2013-03-10 16:00', 'YYYY:MM:DD HH24:MI') AS date_to FROM dual
UNION ALL
SELECT TO_DATE('2013-03-10 15:00', 'YYYY:MM:DD HH24:MI'), TO_DATE('2013-03-10 18:00', 'YYYY:MM:DD HH24:MI') FROM dual
UNION ALL
SELECT TO_DATE('2013-03-10 19:00', 'YYYY:MM:DD HH24:MI'), TO_DATE('2013-03-10 22:00', 'YYYY:MM:DD HH24:MI') FROM dual
)
SELECT FLOOR(sum_diff)
||' days, '||(sum_diff - FLOOR(sum_diff))*24||' hours'
AS hours_between
FROM (SELECT SUM(CASE
WHEN date_from >= TO_DATE(:date_from, 'YYYY-MM-DD HH24:MI')
AND date_to <= TO_DATE(:date_to, 'YYYY-MM-DD HH24:MI') THEN
(date_to - date_from)
WHEN date_from >= TO_DATE(:date_from, 'YYYY-MM-DD HH24:MI')
AND date_to > TO_DATE(:date_to, 'YYYY-MM-DD HH24:MI') THEN
(TO_DATE(:date_to, 'YYYY-MM-DD HH24:MI') - date_from)
WHEN date_from < TO_DATE(:date_from, 'YYYY-MM-DD HH24:MI')
AND date_to <= TO_DATE(:date_to, 'YYYY-MM-DD HH24:MI') THEN
(date_to - TO_DATE(:date_from, 'YYYY-MM-DD HH24:MI'))
WHEN date_from < TO_DATE(:date_from, 'YYYY-MM-DD HH24:MI')
AND date_to > TO_DATE(:date_to, 'YYYY-MM-DD HH24:MI') THEN
(TO_DATE(:date_to, 'YYYY-MM-DD HH24:MI') - TO_DATE(:date_from, 'YYYY-MM-DD HH24:MI'))
ELSE 0
END) AS sum_diff -- The differences are numeric values, hence sum will also be numeric.
FROM daterange dr
WHERE date_to > TO_DATE(:date_from, 'YYYY-MM-DD HH24:MI')
AND date_from < TO_DATE(:date_to, 'YYYY-MM-DD HH24:MI'))
;
注意: WITH
子句仅用于说明目的。在适用的地方替换为您自己的表名。