如何从日历数据库中获取可用时隙列表

时间:2014-09-21 19:04:15

标签: mysql calendar appointment

我有一个事件/日历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是此查询中的null表示此用户没有任何事件,否则将返回每个事件的开头。

因此,如果用户ID出现在上面的查询中并且在start_on列中具有NULL值,则表示该用户全天都可用,因此该用户应该是推荐的5个用户中的1个,因为它具有最高的用户之一可用性。但是,如果用户在数据集中有一个/多个行,并且在开始时具有非空值,那么我们需要查看最接近事件的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

如何提取此数据集?

3 个答案:

答案 0 :(得分:0)

感谢您的帮助编辑了第一个提案,只需要照顾没有任何事件的用户(可以通过'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
祝你好运:)

答案 1 :(得分:0)

这个怎么样:

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月下旬。

答案 2 :(得分:0)

试试这个:

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个。