场景:
预约有开始和结束时间。 预约可以重叠,但出于报告目的,我们需要知道何时存在重叠预约(称为超额预订)以及何时不存在。 两个或多个预约可能会相互重叠,但总有一个预约涉及超额预订,但未归类为超额预订。
规则:
1.预约的重叠部分(片段)被视为超额预订,但其中一次重叠的情况除外,该情况不被视为超额预订。
2.被选择不被视为超额预订的重叠的发生并不重要;它可以是集合中的任何重叠部分。
样本数据:
应用程序ID | 预约开始 | 预约结束 |
---|---|---|
1 | 2:00 | 5:00 |
2 | 3:00 | 6:00 |
3 | 2:00 | 6:00 |
4 | 6:00 | 7:00 |
期望的结果:
应用程序ID | 分类 | 分段开始 | 段结束 |
---|---|---|---|
1 | 没有超额预订 | 2:00 | 5:00 |
2 | 超额预订 | 3:00 | 5:00 |
2 | 没有超额预订 | 5:00 | 6:00 |
3 | 超额预订 | 2:00 | 6:00 |
4 | 没有超额预订 | 6:00 | 7:00 |
...或者...
应用程序ID | 分类 | 分段开始 | 段结束 |
---|---|---|---|
1 | 没有超额预订 | 2:00 | 5:00 |
2 | 超额预订 | 3:00 | 6:00 |
3 | 超额预订 | 2:00 | 5:00 |
3 | 没有超额预订 | 5:00 | 6:00 |
4 | 没有超额预订 | 6:00 | 7:00 |
等等
我尝试过的:
DROP TABLE IF EXISTS #appts
CREATE TABLE #appts
(
appt_id INT
,st TIME
,et TIME
)
INSERT INTO #appts (appt_id,st,et) VALUES (1,'2:00','5:00')
INSERT INTO #appts (appt_id,st,et) VALUES (2,'3:00','6:00')
INSERT INTO #appts (appt_id,st,et) VALUES (3,'2:00','6:00')
INSERT INTO #appts (appt_id,st,et) VALUES (4,'6:00','7:00')
;With a1 AS
(
SELECT * FROM #appts
)
,a2 AS
(
SELECT * FROM a1
)
SELECT DISTINCT
a1.appt_id
,a2.appt_id
,ost = CASE WHEN a2.st > a1.st THEN a2.st ELSE a2.st END
,oet = CASE WHEN a2.et < a1.et THEN a2.et ELSE a1.et END
FROM
a1
INNER JOIN a2
ON (a1.st > a2.st
AND a1.st < a2.et
OR a1.et > a2.st
AND a1.et < a2.et)
WHERE
a1.appt_id < a2.appt_id
appt_id | appt_id | 原 | 最 |
---|---|---|---|
1 | 2 | 3:00 | 5:00 |
1 | 3 | 2:00 | 5:00 |
2 | 3 | 2:00 | 6:00 |
这并没有给我带来可接受的结果集之一。 它似乎为我提供了可能的超额预订,但我需要它也为我提供“未超额预订”,允许每个重叠中的超额预订之一算作未超额预订。
对于 MYSQL 和 comp.:
with Appointments(Appt_ID, Appt_Start, Appt_End) as (
select 1, cast('2:00' as time), cast('5:00' as time) union all
select 2, cast('3:00' as time), cast('6:00' as time) union all
select 3, cast('2:00' as time), cast('6:00' as time) union all
select 4, cast('6:00' as time), cast('7:00' as time)
)
, slices(Appt_Start, Appt_End) as (
select Appt_Start, Appt_End from (
select dt as Appt_Start, lead(dt) over(order by dt, typ) as Appt_End
from (
select Appt_Start as dt, 1 as typ from Appointments
union all
select Appt_End, -1 from Appointments
) d
) d
where Appt_Start < Appt_End
)
select Appt_ID, classification, min(segment_Start) as segment_Start, max(segment_end) as segment_end
from (
select Appt_ID,
case
when rn_by_slice = 1 then 'NOT OVERBOOKED'
else 'OVERBOOKED' end as classification,
segment_Start, segment_end
from (
select d.Appt_ID, s.Appt_Start as segment_Start, s.Appt_End as segment_End,
d.Appt_Start, d.Appt_End,
row_number() over(partition by s.Appt_Start, s.Appt_End order by d.Appt_ID) as rn_by_slice
from slices s
join Appointments d
on least(d.Appt_End - INTERVAL '1' SECOND, s.Appt_End - INTERVAL '1' SECOND) >= greatest(d.Appt_Start, s.Appt_Start)
) d
) d
group by Appt_ID, classification
order by Appt_ID, segment_Start, segment_End
;