我有一套会议室和会议,其中包括开始日期和结束日期。一套会议室属于建筑物。
会议详细信息保存在具有startDate和endDate的MeetingDetail表中。 现在我要在两个时间段之间发出报告,例如reportStartDate和reportEndDate,它会找到为给定建筑物预订所有会议室的时间段
表结构 MEETING_ROOM - ID,ROOMNAME,BUILDING_NO
MEETING_DETAIL - ID,MEETING_ROOM_ID,START_DATE,END_DATE
必须为reportStartDate和REportEndDate
触发查询为了进一步澄清,目的是找到报告的每个时间段内报告的所有时间段:reportStartDate和reportEndDate
答案 0 :(得分:4)
对于SQL Server 2005+,您可以尝试以下(请参阅mysql末尾的注释)
WITH TIME_POINTS (POINT_P) AS
(SELECT DISTINCT START_DATE FROM MEETING_DETAIL
WHERE START_DATE > @reportStartDate AND START_DATE < @reportEndDate
UNION SELECT DISTINCT END_DATE FROM MEETING_DETAIL
WHERE END_DATE > @reportStartDate AND END_DATE < @reportEndDate
UNION SELECT @reportEndDate
UNION SELECT @reportStartDate),
WITH TIME_SLICE (START_T, END_T) AS
(SELECT A.POINT_P, MIN(B.POINT_P) FROM
TIMEPOINTS A
INNER JOIN TIMEPOINTS B ON A.POINT_P > B.POINT_P
GROUP BY A.POINT_P),
WITH SLICE_MEETINGS (START_T, END_T, MEETING_ROOM_ID, BUILDING_NO) AS
(SELECT START_T, END_T, MEETING_ROOM_ID, BUILDING_NO FROM
TIME_SLICE A
INNER JOIN MEETING_DETAIL B ON B.START_DATE <= A.START_T AND B.END_DATE >= B.END_T
INNER JOIN MEETING_ROOM C ON B.MEETING_ROOM_ID = C.ID),
WITH SLICE_COUNT (START_T, END_T, BUILDING_NO, ROOMS_C) AS
(SELECT START_T, END_T, BUILDING_NO, COUNT(MEETING_ROOM_ID) FROM
SLICE_MEETINGS
GROUP BY START_T, END_T, BUILDING_NO),
WITH ROOMS_BUILDING (BUILDING_NO, ROOMS_C) AS
(SELECT BUILDING_NO, COUNT(ID) FROM
MEETING_ROOM
GROUP BY BUILDING_NO)
SELECT B.BUILDING_NO, A.START_T, A.END_T
FROM SLICE_COUNT A.
INNER JOIN ROOMS_BUILDING B WHERE A.BUILDING_NO = B.BUILDING_NO AND B.ROOMS_C = A.ROOMS_C;
它做的是(每一步对应于上面的每个CTE定义)
10.30 11.00 Room1 BuildingA 10.30 11.00 Room2 BuildingA 11.00 12.00 Room1 BuildingA
修改强>
由于mysql不支持WITH子句,因此您必须为上面的每个(5个)WITH clases构造视图。其他一切都会保持不变。
答案 1 :(得分:2)
阅读完评论后,我想我对这个问题的理解有点好。作为第一步,我将使用cross join
:
select *
from (
select distinct start_date
, end_date
from @meeting_detail
) ts
cross join
@meeting_room mr
然后,对于矩阵中的每个单元格,在该时间段中添加会议:
left join
@meeting_detail md
on mr.id = md.meeting_room_id
and ts.start_date < md.end_date
and md.start_date < ts.end_date
然后要求没有免费房间。例如,通过说左连接必须对所有房间和时间段都成功。如果任何字段不为null,则左连接成功:
group by
mr.building_no
, ts.start_date
, ts.end_date
having max(case when md.meeting_room_id is null
then 1 else 0 end) = 0
这是一个完整的工作示例。它是为SQL Server编写的,表变量(@meeting_detail
)在MySQL中不起作用。但报告生成查询应该适用于大多数数据库:
set nocount on
declare @meeting_room table (id int, roomname varchar(50),
building_no int)
declare @meeting_detail table (meeting_room_id int,
start_date datetime, end_date datetime)
insert @meeting_room (id, roomname, building_no)
select 1, 'Kitchen', 6
union all select 2, 'Ballroom', 6
union all select 3, 'Conservatory', 7
union all select 4, 'Dining Room', 7
insert @meeting_detail (meeting_room_id, start_date, end_date)
select 1, '2010-08-01 9:00', '2010-08-01 10:00'
union all select 1, '2010-08-01 10:00', '2010-08-01 11:00'
union all select 2, '2010-08-01 10:00', '2010-08-01 11:00'
union all select 3, '2010-08-01 10:00', '2010-08-01 11:00'
select mr.building_no
, ts.start_date
, ts.end_date
from (
select distinct start_date
, end_date
from @meeting_detail
) ts
cross join
@meeting_room mr
left join
@meeting_detail md
on mr.id = md.meeting_room_id
and ts.start_date < md.end_date
and md.start_date < ts.end_date
group by
mr.building_no
, ts.start_date
, ts.end_date
having max(case when md.meeting_room_id is null
then 1 else 0 end) = 0
打印:
building_no start end
6 2010-08-01 10:00:00.000 2010-08-01 11:00:00.000