【问题标题】:Minimum number of Meeting Rooms required to Accomodate all Meetings in MySQL在 MySQL 中容纳所有会议所需的最小会议室数量
【发布时间】:2020-12-29 18:34:55
【问题描述】:

我在名为 meeting 的表中有以下列: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;

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

【问题讨论】:

标签: mysql sql optimization


【解决方案1】:

假设你有一张这样的名为“会议”的桌子 -

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

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

这看起来更清晰,更简单,效果很好。

【讨论】:

  • @jmoriarty 你能解释一下你的说法吗,因为我使用上面的查询得到了正确的答案。
  • 感谢您的最小解决方案!
【解决方案2】:

会议可以“重叠”。所以,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.

【讨论】:

  • 我完全同意你的观点,SQL/数据库不适用于这类东西。我出于好奇发布了这个。使用编程语言做到这一点既简单又高效。
  • @MontyPython - 是的,它可能在 MySQL 中完成。有时我会咬你的问题,但通常我会说“不要使用 SQL”。 MariaDB 的“序列”表会使它变得容易得多,但仍然不简单。 CTE 可能会有所帮助。也许还有窗口函数。
【解决方案3】:
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

【讨论】:

    【解决方案4】:

    考虑一个表meetings,其中包含id, start_timeend_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;
    

    【讨论】:

      【解决方案5】:

      样本数据:

      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
      );
      

      【讨论】:

        【解决方案6】:

        这是对 gashu 运行良好的代码的解释(或其他关于如何用任何语言解决它的非代码解释)。 首先,如果将变量“minimum_rooms_required”重命名为“重叠”,这将使整个事情更容易理解。因为对于每个开始或结束时间,我们都想知道重叠正在进行的会议的数量。当我们找到最大值时,这意味着没有办法解决小于重叠量的问题,因为它们重叠了。

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

        【讨论】:

          【解决方案7】:

          我会选择 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
          

          【讨论】:

          • 您好,欢迎来到 SO!虽然此代码可能会回答问题,但提供有关它如何和/或为什么解决问题的额外上下文将提高​​答案的长期价值。请阅读tourHow do I write a good answer?
          猜你喜欢
          • 1970-01-01
          • 2018-07-15
          • 1970-01-01
          • 1970-01-01
          • 2016-09-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-08-05
          相关资源
          最近更新 更多