在MySQL中召开所有会议所需的最少会议室数量

时间:2018-01-20 12:46:46

标签: mysql sql optimization

我在名为meetings的表中有以下列:meeting_id - int,start_time - time,end_time - time。假设此表仅包含一个日历日的数据,我需要多少最小数量的房间来容纳所有会议。参加会议的人数/人数并不重要。

以下是解决方案:

select * from
(select t.start_time, 
        t.end_time, 
        count(*) - 1 overlapping_meetings, 
        count(*) minimum_rooms_required,
        group_concat(distinct concat(y.start_time,' to ',t.end_time) 
separator ' // ') meeting_details from 
(select 1 meeting_id, '08:00' start_time, '09:15' end_time union all
select 2, '13:20', '15:20' union all
select 3, '10:00', '14:00' union all
select 4, '13:55', '16:25' union all
select 5, '14:00', '17:45' union all
select 6, '14:05', '17:45') t left join 

(select 1 meeting_id, '08:00' start_time, '09:15' end_time union all
select 2, '13:20', '15:20' union all
select 3, '10:00', '14:00' union all
select 4, '13:55', '16:25' union all
select 5, '14:00', '17:45' union all
select 6, '14:05', '17:45') y

on t.start_time between y.start_time and y.end_time

group by start_time, end_time) z;

我的问题 - 这个答案有什么问题吗?即使这没有任何问题,有人可以分享更好的答案吗?

7 个答案:

答案 0 :(得分:4)

会议可以重叠"。因此,GROUP BY start_time, end_time无法解决这个问题。

并非每种算法都可以在SQL中完成。或者,至少,它可能非常低效。

我会使用真正的编程语言进行计算,让数据库保持擅长的状态 - 作为数据存储库。

Build a array of 1440 (minutes in a day) entries; initialize to 0.
Foreach meeting:
    Foreach minute in the meeting (excluding last minute):
        increment element in array.
Find the largest element in the array -- the number of rooms needed.

答案 1 :(得分:3)

我们假设您有一张名为“会议”的表格。像这样 -

enter image description here

然后,您可以使用此查询获得容纳所有会议所需的最少会议室数。

select max(minimum_rooms_required) from (select count(*) minimum_rooms_required from meetings t left join meetings y on t.start_time between y.start_time and y.end_time group by t.id) z;

这看起来更清晰,更简单,工作正常。

答案 2 :(得分:1)

CREATE TABLE [dbo].[Meetings](
[id] [int] NOT NULL,
[Starttime] [time](7) NOT NULL,
[EndTime] [time](7) NOT NULL) ON [PRIMARY] )GO

样本数据集:

INSERT INTO Meetings VALUES (1,'8:00','09:00')
INSERT INTO Meetings VALUES (2,'8:00','10:00')
INSERT INTO Meetings VALUES (3,'10:00','11:00')
INSERT INTO Meetings VALUES (4,'11:00','12:00')
INSERT INTO Meetings VALUES (5,'11:00','13:00')
INSERT INTO Meetings VALUES (6,'13:00','14:00')
INSERT INTO Meetings VALUES (7,'13:00','15:00')

要查找所需的最小房间数,请运行以下查询:

create table #TempMeeting
(
 id int,Starttime time,EndTime time,MeetingRoomNo int,Rownumber int
)
insert into #TempMeeting select id, Starttime,EndTime,0 as MeetingRoomNo,ROW_NUMBER() 
over (order by starttime asc) as Rownumber from Meetings

declare @RowCounter int
select top 1 @RowCounter=Rownumber from #TempMeeting order by Rownumber

WHILE  @RowCounter<=(Select count(*) from #TempMeeting)
BEGIN
     update #TempMeeting set MeetingRoomNo=1
     where Rownumber=(select top 1 Rownumber from #TempMeeting where 
     Rownumber>@RowCounter and Starttime>=(select top 1 EndTime from #TempMeeting 
     where Rownumber=@RowCounter)and MeetingRoomNo=0)set @RowCounter=@RowCounter+1
END

select count(*) from #TempMeeting where MeetingRoomNo=0

答案 3 :(得分:0)

请考虑具有列meetingsid, start_time的表end_time。然后,以下查询应给出正确答案。

with mod_meetings as (select id, to_timestamp(start_time, 'HH24:MI')::TIME as start_time,
to_timestamp(end_time, 'HH24:MI')::TIME as end_time from meetings)
select CASE when max(a_cnt)>1 then max(a_cnt)+1 
            when max(a_cnt)=1 and max(b_cnt)=1 then 2 else 1 end as rooms 
from
(select count(*) as a_cnt, a.id, count(b.id) as b_cnt from mod_meetings a left join mod_meetings b 
on a.start_time>b.start_time and a.start_time<b.end_time group by a.id) join_table;

答案 4 :(得分:0)

样本数据:

DROP TABLE IF EXISTS meeting;
CREATE TABLE "meeting" (
"meeting_id"    INTEGER NOT NULL UNIQUE,
"start_time"    TEXT NOT NULL,
"end_time"  TEXT NOT NULL,
PRIMARY KEY("meeting_id")
);

INSERT INTO meeting values (1,'08:00','14:00');
INSERT INTO meeting values (2,'09:00','10:30');
INSERT INTO meeting values (3,'11:00','12:00');
INSERT INTO meeting values (4,'12:00','13:00');
INSERT INTO meeting values (5,'10:15','11:00');
INSERT INTO meeting values (6,'12:00','13:00');
INSERT INTO meeting values (7,'10:00','10:30');
INSERT INTO meeting values (8,'11:00','13:00');
INSERT INTO meeting values (9,'11:00','14:00');
INSERT INTO meeting values (10,'12:00','14:00');
INSERT INTO meeting values (11,'10:00','14:00');
INSERT INTO meeting values (12,'12:00','14:00');
INSERT INTO meeting values (13,'10:00','14:00');
INSERT INTO meeting values (14,'13:00','14:00');

解决方案:

DROP VIEW IF EXISTS Final;
CREATE VIEW Final AS SELECT time, group_concat(event), sum(num) num from (
select start_time time, 's' event, 1 num from meeting
union all 
select end_time time, 'e' event, -1 num from meeting)
group by 1
order by 1;

select max(room) AS Min_Rooms_Required FROM (
    select 
        a.time,
        sum(b.num) as room
    from 
        Final a
        , Final b
    where a.time >= b.time
    group by a.time
    order by a.time
);

答案 5 :(得分:0)

以下是gashu正常工作的代码的说明(或者其他非代码说明,说明如何使用任何语言解决该问题)。 首先,如果将变量“ minimum_rooms_required”重命名为“ overlap”,则整个内容将更易于理解。因为对于每个开始时间或结束时间,我们都想知道进行中的重叠会议的数量。当我们找到最大值时,这意味着没有比重叠的数量少的东西了,因为它们重叠了。

顺便说一句,我认为代码可能有错误。它应该检查y.start_time和y.end_time之间的t.start_time或t.end_time。反例:会议1开始于8:00,结束于11:00,会议2开始于10:00,结束于12:00。 (我把它作为对加舒的回答的评论,但我没有足够的声誉)

答案 6 :(得分:0)

我会选择 Lead() 分析函数

select 
sum(needs_room_ind) as min_rooms
from (
      select
      id,
      start_time,
      end_time,
      case when lead(start_time,1) over (order by start_time asc) between start_time 
      and end_time then 1 else 0 end as needs_room_ind
      from
      meetings
   ) a
相关问题