如何使用日期范围查找最重叠的时间段

Oli*_*tin 5 sql oracle time date

假设您有一个包含标识符,开始时间和结束时间的表.这些开始和结束时间可以是任何时间长度.开始时间始终在结束时间之前.假设没有空值.

什么样的查询会告诉我最"流行"的时间,即每行中的两个范围与其他大多数行重叠?

这是一个真实的应用程序,它是一个记录用户登录和登出时间的表格.我想写一个查询,告诉我什么时候大多数并发用户登录,看看这是什么时间.

谢谢.

Gor*_*off 7

有几种方法可以解决这个问题.一个使用相关子查询.那不是很有趣.相反,让我们使用累积和方法,因为你有Oracle.

关键是从一个时间戳列表开始,一个值为+1,一个开头为-1,结束时为-1.这很简单:

select t.*
from ((select starttime as thetime, 1 as value from table t) union all
      (select endtime, -1 as value from table t)
     ) t
Run Code Online (Sandbox Code Playgroud)

现在,累积总和value告诉您在任何给定时间的活动重叠次数:

select t.*, sum(value) over (order by thetime) as numactives
from ((select starttime as thetime, 1 as value from table t) union all
      (select endtime, -1 as value from table t)
     ) t
Run Code Online (Sandbox Code Playgroud)

这解决了您的问题.您可能想要order by numactives desc在特定时间添加一个.


Luk*_*der 5

这是一个使用简单自连接的示例解决方案,并且GROUP BY:

WITH d(id, t1, t2) AS (
    SELECT 1, date '2010-01-01', date '2010-03-01' FROM DUAL UNION ALL
    SELECT 2, date '2010-02-01', date '2010-04-01' FROM DUAL UNION ALL
    SELECT 3, date '2010-02-01', date '2010-04-01' FROM DUAL UNION ALL
    SELECT 4, date '2010-01-01', date '2010-01-03' FROM DUAL UNION ALL
    SELECT 5, date '2011-01-01', date '2011-02-15' FROM DUAL
)
SELECT d1.id, d1.t1, d1.t2, 
       COUNT(*) "Overlap count", 
       LISTAGG('[' || d2.t1 || ', ' || d2.t2 || ']', ', ')
       WITHIN GROUP (ORDER BY d2.id) "Overlapping intervals"
FROM d d1 
LEFT OUTER JOIN d d2 
ON d2.t1 <= d1.t2 AND d1.t1 <= d2.t2
GROUP BY d1.id, d1.t1, d1.t2
ORDER BY COUNT(*) DESC
Run Code Online (Sandbox Code Playgroud)

"Overlapping intervals"聚合是仅用于说明.

SQLFiddle

...输出:

| ID | OVERLAP COUNT |                                                                          OVERLAPPING INTERVALS |
|----|---------------|------------------------------------------------------------------------------------------------|
|  1 |             4 | [01-JAN-10, 01-MAR-10], [01-FEB-10, 01-APR-10], [01-FEB-10, 01-APR-10], [01-JAN-10, 03-JAN-10] |
|  2 |             3 |                         [01-JAN-10, 01-MAR-10], [01-FEB-10, 01-APR-10], [01-FEB-10, 01-APR-10] |
|  3 |             3 |                         [01-JAN-10, 01-MAR-10], [01-FEB-10, 01-APR-10], [01-FEB-10, 01-APR-10] |
|  4 |             2 |                                                 [01-JAN-10, 01-MAR-10], [01-JAN-10, 03-JAN-10] |
|  5 |             1 |                                                                         [01-JAN-11, 15-FEB-11] |
Run Code Online (Sandbox Code Playgroud)