2014-09-21 3 views
2

У меня есть таблица событий/календарей MySQL, в которой каждый пользователь имеет несколько встреч/событий в течение дня. Если один пользователь не может выполнить эту встречу/мероприятие «потому что он/она работает за другим назначением», мне нужно иметь возможность повторно назначить эту встречу другому доступному пользователю. Поэтому мне нужно отобразить предложение пяти лучших пользователей, которые доступны для запланированного периода времени, и может принять это назначение, менеджер сможет повторно назначить эту встречу одному из предложенных пользователей.Как получить список доступных временных интервалов из базы данных календаря

Моя таблица событий выглядит примерно так

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 в этом запросе, это означает, что у этого пользователя нет никакого события, иначе он вернет начало каждого события.

Так, если идентификатор пользователя отображается в запросе выше и имеет значение NULL в столбце start_on, это означает, что этот пользователь доступен весь день, поэтому этот пользователь должен быть 1 из 5 пользователей, рекомендующих, поскольку он имеет один из максимально высокий доступность. Но если пользователь имеет одну или несколько строк в наборе данных с ненулевым значением в начале, то нам нужно посмотреть на 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 

Как извлечь этот набор данных?

ответ

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 

Удачи :)

+0

он не работает. Кроме того, event_type не должен быть фактором. Независимо от типа события, у каждого есть возможность принять следующую встречу. Не работает означает, что предлагаемый владелец является тем же именем, что и org_owner. org_owner должен отличаться от того, что предложенным пользователем является предлагаемый владелец - новый доступный пользователь. – Jaylen

+0

Я создал таблицу и заполнил данные и, похоже, работает для меня. Можете ли вы предоставить небольшую часть данных? Спасибо. Редактирование: просто увидели объяснение о имени, будет ли оно работать, просто добавив 'cal_avail.owner_id <> calendar_events.user_id' для последнего предложения 'on'? – nicolas

+0

Это не сработало. Вот скрипка, которую я создал с некоторыми данными, чтобы дать вам некоторые данные. Http://sqlfiddle.com/#!9/8374f/1 Обратите внимание, что запрос я сужу запрос до event_id = 52, поэтому я могу найти для него 3 предложенных пользователя – Jaylen

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, я только сделал предположение, что окончание daay 6 PM

+0

Примечание: вам необходимо выполнить два запроса – Gervs

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.

Смежные вопросы