【问题标题】:How to get a list of available time slots from calendar database如何从日历数据库中获取可用时间段列表
【发布时间】:2014-11-15 18:05:24
【问题描述】:

我有一个事件/日历 MySQL 表,其中每个用户全天都有多个约会/事件。如果一个用户无法进行该约会/事件“因为他/她在其他约会上落后”,我需要能够将此约会重新分配给另一个可用用户。因此,我需要显示在预定时间范围内可用并且可以接受此约会的前 5 位用户的建议,经理将能够将此约会重新分配给建议的用户之一。

我的事件表看起来像这样

CREATE TABLE `calendar_events` (
   `event_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
   `start_on` datetime NOT NULL,
   `end_on` datetime NOT NULL,
   `subject` varchar(255) NOT NULL,
   `event_type` enum('Phone Call','Meeting','Event','Appointment','Other') CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL DEFAULT 'Phone Call',
   `all_day_event` tinyint(1) DEFAULT '0' COMMENT '1 = all day event, 0 = no',
   `phone_call_id` int(11) unsigned DEFAULT NULL,
   `account_id` int(11) unsigned DEFAULT NULL,
   `client_id` int(11) unsigned DEFAULT NULL,
   `owner_id` int(11) unsigned NOT NULL,
   `created_by` int(11) unsigned NOT NULL,
   `created_on` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
   `modified_by` int(11) unsigned DEFAULT NULL,
   `modified_on` datetime DEFAULT NULL,
   `event_location` varchar(255) DEFAULT NULL,
   `event_notes` varchar(10000) DEFAULT NULL,
   `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '0 = purged, 1 = active, 2=pass, 3 = cancled, 5 = waiting for auditor to be enabled',
   PRIMARY KEY (`event_id`),
   UNIQUE KEY `phone_call_id` (`phone_call_id`,`account_id`,`client_id`),
   KEY `client_id` (`client_id`),
   KEY `account_id` (`account_id`)
 ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

所以让我们将 event_id = 100 分配给 user_id = 2 并安排为 start_on = '2014-09-21 10:00:00' 和 end_on '2014-09-21 10:00:00'

并且 user_id = 5 有约会 start_on '2014-09-21 11:45:00' 和 end_on '2014-09-21 12:30:00'

并且 user_id = 2 无法进行安排在 '2014-09-21 10:00:00' 的约会,因此系统会建议 user_id = 5,因为他将在接下来的 105 分钟内进行。

最终的数据集需要是

event_id org_owner  suggested_owner   available_for
100      2          5                 105

以下查询将为我提供users 表中所有可用用户的列表以及 start_on end_on 值,如果用户安排了一个事件(一个用户可以有多个记录)。如果 start_on 在这个查询意味着这个用户没有任何事件,否则它将返回每个事件的开始。

因此,如果用户 ID 出现在上面的查询中并且在 start_on 列中具有 NULL 值,这意味着该用户全天都可用,因此该用户应该是要推荐的 5 个用户中的 1 个,因为它是最高的用户之一可用性。但是如果一个用户在数据集中有一个/多行并且start on then中的值是非空的,我们需要查看最接近事件的start_on,然后推荐具有最大可用性的前5个价值。

SELECT user_id, start_on, end_on, subject
FROM view_users AS su
LEFT JOIN calendar_events AS c ON c.owner_id = su.user_id AND c.start_on NOT BETWEEN '2014-09-30 00:00:00' AND '2014-09-30 23:59:59' AND c.status = 1
WHERE su.is_available_today = 1

如何提取此数据集?

【问题讨论】:

    标签: mysql calendar appointment


    【解决方案1】:

    在您的帮助下编辑了第一个提案,只需要照顾没有任何事件的用户(可以通过“t”子查询中的左连接来实现)。这可以改进很多,但现在我有点累了:)

    SELECT
    c.event_id,                     -- Event id
    c.owner_id AS org_owner,        -- Original owner of event
    t.owner_id AS suggested_owner,  -- Suggested new user
    c.start_on,                     -- Event start
    t.free_from,                    -- Owner free slot start
    t.free_to,                  -- Owner free slot end
    TIME_TO_SEC( TIMEDIFF( t.free_to, c.start_on ) ) /60 AS available_for   -- Availibility of minutes (diff between event start and free slot end)
    
    FROM calendar_events AS c
    
    -- Join with free slots
    LEFT JOIN (
        -- Add a slot for beginning, 1999-01-01 to first event start
        SELECT * FROM (
            SELECT owner_id, '1900-01-01' AS free_from, MIN( start_on ) AS free_to
            FROM calendar_events c3
            GROUP BY owner_id
        ) AS deb
    
        UNION
    
        -- select free slots by taking the event end and the following event start
        SELECT owner_id, `end_on` AS free_from, (
            SELECT start_on
            FROM calendar_events c2
            WHERE c2.owner_id = c1.owner_id
            AND c2.start_on > c1.end_on
            ORDER BY c2.start_on
            LIMIT 0 , 1
        ) AS free_to
    
        FROM calendar_events c1
    
        UNION 
    
        -- Add a slot for end, last event end to 2100-01-01
        SELECT * FROM (
            SELECT owner_id, MAX( end_on ) AS free_from, '2100-01-01' AS free_to
            FROM calendar_events c3
            GROUP BY owner_id
        ) AS end
    ) AS t ON t.owner_id <> c.owner_id
    -- Join avoid using same user and ensure free slot matches event dates
    AND t.free_from <= c.start_on AND t.free_to >= c.end_on
    WHERE c.status = 1
    AND c.event_id =52
    GROUP BY t.owner_id     -- To avoid multiple free slots by user
    ORDER BY available_for DESC -- Sort to list biggest slots first
    LIMIT 0, 5              -- Only five first matching users
    

    祝你好运:)

    【讨论】:

    • 它不工作。此外, event_type 不应该是因素。无论事件类型如何,每个人都可以参加下一次约会。不工作意味着建议的所有者与 org_owner 的名称相同。 org_owner 必须不同于作为建议所有者的建议所有者是新的可用用户。
    • 我已经创建了表格并填充了数据,它似乎对我有用。能提供一小部分数据吗?谢谢编辑:刚刚看到有关名称的解释,只需将“cal_avail.owner_id calendar_events.user_id”添加到最后一个“on”子句即可吗?
    • 那也没用。这是我用一些数据创建的小提琴,为您提供一些数据sqlfiddle.com/#!9/8374f/1 请注意,我将查询范围缩小到 event_id=52,因此我可以找到 3 个建议的用户
    • 谢谢,我明白了。再精确一点:这是一个定义用户不能预约的用户吗?
    • 用户 2 将向用户 10(经理)发送消息并说他们可以进行此约会。因此,用户 10 将查看所有者迟到的约会列表,他们需要查看可用用户接听电话的建议。如果有帮助,有一个用户表,其中列出了所有正在工作的用户。
    【解决方案2】:

    这个怎么样:

    SELECT event_id, owner_id, start_on INTO @eventid, @user, @start_on 
    FROM calender_events WHERE event_id = 100;
    
    SELECT @event_id event_id,
        @user org_owner,
        c.owner_id suggested_owner,
        TIMESTAMPDIFF(MINUTE, $start_on, COALESCE(c.min_start, DATE(@start_on) + INTERVAL 18 HOUR)) available_for
    FROM
        users u
    LEFT JOIN
        (SELECT
              owner_id,
              MIN(start_on) 
         FROM
              calender_events
         WHERE
              (start_on BETWEEN @start_on AND DATE(@start_on) + INTERVAL 18 HOUR) 
              OR
              (start_on BETWEEN DATE(@start_on) AND DATE(@start_on) + INTERVAL 18 HOUR AND all_day_event = 1)
         GROUP BY owner_id
        ) c
        ON u.user_id = c.owner_id
    WHERE u.user_id <> @user
    ORDER BY available_for DESC
    LIMIT 5
    

    也许你必须调整 INTERVAL,我只是假设当天下午 6 点结束

    【讨论】:

    • 注意:你必须执行两个查询
    【解决方案3】:

    试试这个:

    SELECT
        co.event_id,
        co.owner_id org_owner,
        su.user_id suggested_owner,
        ifnull(min((to_seconds(c.start_on) - to_seconds(co)) / 60), 999) available
    FROM calendar_events co
    CROSS JOIN view_users su
    LEFT JOIN calendar_events c ON c.owner_id = su.user_id
        AND c.start_on BETWEEN co.start_on AND date(adddate(co.start_on, 1))
        AND c.status = 1
    WHERE co.event_id = 100
    AND su.is_available_today = 1
    GROUP BY 1, 2, 3
    ORDER BY 4 DESC
    LIMIT 5
    

    在目标事件后的第二天没有约会的用户被分配了“999”的可用值,将他们放在列表的顶部。

    每个用户的下一个事件使用min() 在时间间隔内找到,所有用户都按时间间隔最大排序,limit 为您提供前 5 个。

    【讨论】:

      猜你喜欢
      • 2021-05-12
      • 1970-01-01
      • 2019-08-23
      • 1970-01-01
      • 1970-01-01
      • 2011-05-21
      • 1970-01-01
      • 2019-12-14
      • 1970-01-01
      相关资源
      最近更新 更多