@Mixelv

[MySQL] Как выбрать свободные кабинеты по интервалу дат?

Имеется 2 таблицы:

cabinets:
- id (PRIMARY KEY)
- name (VARCHAR 64)
... (ещё куча полей для фильтров) ...

busy:
- cabinet_id (не уникальное)
- date_start (DATE)
- date_end (DATE)

Нужно, имея дату начала ($s) и окончания ($e) занятий, выбрать доступные кабинеты.

Приходит в голову что-то вроде..

SELECT c.name 
FROM cabinets c 
WHERE NOT (
SELECT COUNT(cabinet_id) 
FROM busy b 
WHERE 
b.cabinet_id = c.id AND ( date_start < $e AND date_end > $s ) 
)


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

Как это сделать правильно?
  • Вопрос задан
  • 2743 просмотра
Решения вопроса 1
Rsa97
@Rsa97
Для правильного вопроса надо знать половину ответа
Нужны кабинеты, полностью свободные на весь заданный интервал? Тогда так:
SELECT `c`.`name`
    FROM `cabinets` AS `c`
    WHERE `c`.`id` NOT IN (
        SELECT DISTINCT `b`.`cabinet_id`
            FROM `busy` AS `b` 
            WHERE `b`.`date_start` BETWEEN {$s} AND {$e} 
                OR {$s} BETWEEN `b`.`date_start` AND `b`.`date_end`
    )
Ответ написан
Пригласить эксперта
Ответы на вопрос 3
@rowdyro
SELECT c.name
FROM cabinets c
WHERE NOT EXISTS(
SELECT cabinet_id
FROM busy b
WHERE
b.cabinet_id = c.id AND ( b.date_start < $e AND b.date_end > $s )
)

побыстрее будет
Ответ написан
Комментировать
Immortal_pony
@Immortal_pony Куратор тега MySQL
SELECT 
    c.`name` 
FROM cabinets c 
WHERE c.`id` NOT IN (
    SELECT DISTINCT
        b.`cabinet_id`
    FROM busy b 
    WHERE date_start >= $s 
    AND date_end < $e
)
Ответ написан
Комментировать
@Vampiro
Не пробовал, но я бы делал так: поле date - хранит день в который кабинет занят, а часы я бы хранил маской (24 бита хватит как раз) тогда выбрав занятые кабинеты в нужный день (это можно сделать по индексу) останется сделать фулскан с битовой операцией.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы