1

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

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

4

3 回答 3

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

小提琴

于 2013-03-20T08:10:28.380 回答
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'
     );

在这里 看小提琴

于 2013-03-20T07:41:55.273 回答
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子句仅用于说明目的。在适用的情况下替换为您自己的表名。

于 2013-03-20T09:22:40.007 回答