我有一张包含开始时间,结束时间和日期的表格。 我需要的是通过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
答案 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:00
和2017-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;