查找范围列表所涵盖的日期范围内的总持续时间

时间:2013-03-20 04:52:19

标签: sql oracle intervals date-range

我有一堆日期范围存储在表格的记录中,其中许多重叠。

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,因此在迁移完成之前,我无法使用任何特定于任何版本的内容。

3 个答案:

答案 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

fiddle

答案 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子句仅用于说明目的。在适用的地方替换为您自己的表名。