Подскажите, как найти свободные 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;
Комментариев нет:
Отправить комментарий