如何获取数据库中表的空闲时间?

时间:2017-04-10 06:55:38

标签: sql oracle

我有一张包含开始时间,结束时间和日期的表格。 我需要的是通过sql查询显示可用的空闲时间和相同的时间范围,具体取决于日期。

查询仅显示未占用的空闲时间。 屏幕上的输出看起来像这样

Date : 01/08/2017  starhour : 20:00 endhour : 21:00 duration : 60   

这是我到目前为止所做的:

SELECT * 
FROM ( SELECT DISTINCT date, starthour, endhour 
       FROM diary 
       WHERE diary_id = 1025 
       AND date = TO_DATE('2017-05-01','yyyy/MM/dd') 
       AND ( starthour >= to_timestamp('11:00:00.01','HH24:MI:SS.FF') 
         AND endhour <= to_timestamp('11:15:00.01','HH24:MI:SS.FF')
           ) 
    ) ORDER BY date ASC, starthour ASC

1 个答案:

答案 0 :(得分:0)

Oracle安装程序

CREATE TABLE diary ( "DATE", starthour, endhour ) AS
  SELECT DATE '2017-04-10', '12:00', '12:15' FROM DUAL UNION ALL
  SELECT DATE '2017-04-10', '12:15', '12:30' FROM DUAL UNION ALL -- Immediately follows
  SELECT DATE '2017-04-10', '12:45', '13:15' FROM DUAL UNION ALL
  SELECT DATE '2017-04-10', '13:00', '14:00' FROM DUAL UNION ALL -- Partly overlaps
  SELECT DATE '2017-04-10', '14:30', '15:30' FROM DUAL UNION ALL
  SELECT DATE '2017-04-10', '14:45', '15:15' FROM DUAL UNION ALL -- Inside previous
  SELECT DATE '2017-04-10', '16:00', '17:00' FROM DUAL;

<强>查询

WITH dates ( starthour, endhour ) AS (
  -- Convert your dates to include time components.

  SELECT "DATE" + TO_DATE( starthour, 'HH24:MI' ) - TO_DATE( '00:00', 'HH24:MI' ) ),
         "DATE" + TO_DATE( endhour,   'HH24:MI' ) - TO_DATE( '00:00', 'HH24:MI' ) )
  FROM   diary
  WHERE  "DATE" + TO_DATE( starthour, 'HH24:MI' ) - TO_DATE( '00:00', 'HH24:MI' ) )
           < :your_end_date
  AND    "DATE" + TO_DATE( endhour,   'HH24:MI' ) - TO_DATE( '00:00', 'HH24:MI' ) )
           > :your_start_date

  -- Add zero width entries at the start and end of the range:

  UNION ALL SELECT :your_start_date, :your_start_date FROM DUAL
  UNION ALL SELECT :your_end_date,   :your_end_date   FROM DUAL
),
unpivoted ( datetime, isStartEnd, cnt ) AS (
  -- Convert pairs of start/end times to a list of times
  -- where the start of an appointment has a corresponding value of +1 and the
  -- end of an appointment has a corresponding value of -1. The CNT column
  -- is the total of all the previous +1 / -1 values.

  SELECT datetime,
         isStartEnd,
         SUM( isStartEnd ) OVER ( ORDER BY datetime ASC, isStartEnd DESC )
  FROM   dates
  UNPIVOT ( datetime FOR isStartEnd IN ( starthour AS 1, endhour AS -1 ) )
),
appointment_bounds ( startdate, enddate, isStartEnd ) AS (
  SELECT LAG( datetime, 1 ) OVER ( ORDER BY datetime ASC, isStartEnd DESC ),
         datetime,
         isStartEnd
  FROM   unpivoted
  WHERE  ( cnt = 0 AND isStartEnd = -1 ) -- Last time in a group of appointments
  OR     ( cnt = 1 AND isStartEnd =  1 ) -- First time in a group of appointments
)
SELECT startdate,
       enddate
FROM   appointment_bounds
WHERE  isStartEnd = 1
AND    startdate IS NOT NULL;

<强>输出

分别使用绑定参数:your_start_date:your_end_date作为2017-04-10 11:00:002017-04-10 16:30:00运行上述查询:

STARTDATE           ENDDATE
------------------- -------------------
2017-04-10 11:00:00 2017-04-10 12:00:00
2017-04-10 12:30:00 2017-04-10 12:45:00
2017-04-10 14:00:00 2017-04-10 14:30:00
2017-04-10 15:30:00 2017-04-10 16:00:00

更简单查询

WITH dates ( starthour, endhour ) AS (
  -- Convert your dates to include time components.

  SELECT "DATE" + TO_DATE( starthour, 'HH24:MI' ) - TO_DATE( '00:00', 'HH24:MI' ) ),
         "DATE" + TO_DATE( endhour,   'HH24:MI' ) - TO_DATE( '00:00', 'HH24:MI' ) )
  FROM   diary
  WHERE  "DATE" + TO_DATE( starthour, 'HH24:MI' ) - TO_DATE( '00:00', 'HH24:MI' ) )
           < :your_end_date
  AND    "DATE" + TO_DATE( endhour,   'HH24:MI' ) - TO_DATE( '00:00', 'HH24:MI' ) )
           > :your_start_date

  -- Add zero width entries at the start and end of the range:

  UNION ALL SELECT :your_start_date, :your_start_date FROM DUAL
  UNION ALL SELECT :your_end_date,   :your_end_date   FROM DUAL
)
SELECT prev_endhour, starthour
FROM   (
  SELECT LAG( endhour ) OVER ( ORDER BY starthour ASC, endhour ASC ) AS prev_endhour,
         starthour
  FROM   dates
)
WHERE prev_endhour < starthour;