Страницы

Поиск по вопросам

понедельник, 8 июля 2019 г.

Найти свободные строки в промежутках дат

Подскажите, как найти свободные classrooms.classroom_id для определенного services.service_id: такие, что не находятся в services_classrooms, или такие, что даты определенного services.service_id: services.service_start и services.service_end не пересекаются с датами других services.service_id связанных с classrooms.classroom_id находящимся в services_classrooms (Рис. 1)
Рис. 1

mysql> show columns from classrooms; +--------------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------------+-------------+------+-----+---------+----------------+ | classroom_id | int(11) | NO | PRI | NULL | auto_increment | | classroom | varchar(10) | NO | UNI | NULL | | +--------------+-------------+------+-----+---------+----------------+ mysql> show columns from services_classrooms; +--------------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------------+---------+------+-----+---------+-------+ | classroom_id | int(11) | NO | PRI | NULL | | | service_id | int(11) | NO | PRI | NULL | | +--------------+---------+------+-----+---------+-------+ mysql> show columns from services; +---------------+----------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------------+----------+------+-----+---------+----------------+ | service_id | int(11) | NO | PRI | NULL | auto_increment | | lesson_id | int(11) | NO | MUL | NULL | | | worth_id | int(11) | NO | MUL | NULL | | | service_end | datetime | NO | | NULL | | | service_start | datetime | NO | | NULL | | +---------------+----------+------+-----+---------+----------------+


Ответ

Вариант без UNION и вложенных запросов. Так же, дополнительно проверяет на пересечение аудитории текущего сервиса с другими сервисами в таблице.
SELECT c.classroom_id, c.classroom FROM services s -- перебираем все аудитории JOIN classrooms c ON (1 = 1) -- ищем все сервисы привязанные к аудиториям LEFT JOIN services s1 ON s1.classroom_id = c.classroom_id -- сервис для которого ищем свободные аудитории WHERE s.service_id = 1 -- группируем полученные записи по аудиториям GROUP BY c.classroom_id, c.classroom -- ищем минимальное значение в группировке по условиям -- если минимальное значение равно 1, то аудитория доступна HAVING MIN(CASE -- если у сервиса уже назначена эта аудитория WHEN s.classroom_id = c.classroom_id AND s.service_id = s1.service_id THEN 1 -- если аудитория заданная у сервиса s1 не пересекается по датам с сервисом s WHEN (s.service_start >= s1.service_end OR s.service_end <= s1.service_start) AND s.service_id <> s1.service_id THEN 1 -- если у аудитории нет ни одного назначенного сервиса WHEN (s1.service_id IS NULL) THEN 1 -- иначе будет 0 ELSE 0 END) = 1;

Комментариев нет:

Отправить комментарий