Поиск свободного времени в календаре с MySQL - PullRequest
1 голос
/ 28 марта 2020

У меня есть таблица пользователей, в которой я храню информацию о пользователях вместе с их временем начала и окончания дня

id    day_start    day_end
1     08:00:00     16:00:00
2     09:00:00     18:00:00        

, а есть еще одна таблица, в которой хранятся события календаря для пользователей

id    user_id    start                    end
1     1          2020-01-12 12:00:00      2020-01-12 13:30:00
2     1          2020-01-12 13:30:00      2020-01-12 14:30:00
3     1          2020-01-12 09:00:00      2020-01-12 10:30:00

Поэтому я пытаюсь отфильтровать этих людей по их свободному времени. т.е. я хочу предоставить время начала, время окончания и массив дней недели и найти пользователей, которые доступны на основе этих критериев. Например, я хочу сказать, что я ищу людей, которые доступны по субботам или понедельникам в любое время с 10:00:00 до 14:00:00 и получают список пользователей.

Обратите внимание, что Пользователь может быть недоступен в течение всего запрашиваемого времени, но только в течение части времени. Например, пользователь, у которого есть свободное время только в субботу с 11:00:00 до 11:30:00, также должен быть указан.

Я ищу запрос MySQL для реализации этой функции.

Если бы запрос мог дать время начала и окончания всех свободных временных интервалов, было бы здорово. как то так

user_id    start                    end
1          2020-01-12 08:00:00      2020-01-12 09:00:00
1          2020-01-12 10:30:00      2020-01-12 12:00:00
1          2020-01-12 14:30:00      2020-01-12 18:00:00
2          ...
...

1 Ответ

1 голос
/ 28 марта 2020

Вот один вариант, использующий оконные функции и выражение общей таблицы (оба доступны только в MySQL 8.0).

Для начала вы можете объединить обе таблицы и использовать lag() для получения конец предыдущего события. Затем вы можете вытащить интервалы путем поиска несмежных строк. Первый интервал определяется тем, что у него нет предыдущего события. Чтобы получить последний интервал, мы используем union all и снова выбираем из cte.

with cte as (
    select
        e.*,
        u.day_start,
        u.day_end,
        lag(e.dt_end) over(partition by u.id order by e.dt_start) lag_dt_end
    from events e
    inner join users u on u.id = e.user_id
)
select
    user_id,
    coalesce(lag_dt_end, concat(date(dt_start), ' ', day_start)) dt_start,
    dt_start dt_end
from cte
where 
    dt_start <> lag_dt_end 
    or (lag_dt_end is null and time(dt_start) > day_start)
union all
select 
    user_id, 
    max(dt_end), 
    concat(date(max(dt_end)), ' ', day_end)
from cte
group by user_id, day_end
having time(max(dt_end)) < day_end

Демонстрация на DB Fiddle :

user_id | dt_start            | dt_end             
------: | :------------------ | :------------------
      1 | 2020-01-12 08:00:00 | 2020-01-12 09:00:00
      1 | 2020-01-12 10:30:00 | 2020-01-12 12:00:00
      1 | 2020-01-12 14:30:00 | 2020-01-12 16:00:00
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...