|
|
|
| Добрый день.
Задача следующая:
Есть расписание работы врача в виде часовых временных интервалов:
date start finish
2011-08-15 10 13
2011-08-15 14 19
Значит врач работает с 10 до 19 с перерывом на обед 13-14.
Врач принимает пациентов:
date start length (длительность приема в минутах)
2011-08-15 10.15 45
2011-08-15 11.30 30
2011-08-15 14.00 60
Значит у врача 3 приема, в течении которых он занят.
Производится поиск по расписанию врача для того, чтобы записаться к нему с заранее известной длительностью приема.
Скажем, я хочу записаться к врачу на прием, который будет длиться полтора часа.
Свободные интервалы врача (по данным выше): 10.00-10.15; 11.00-11.30; 12.00-13.00; 15.00-19.00.
Значит сегодня я смогу "влезть" только в интервал с 15.00 до 19.00.
Вопрос: как получить эти свободные интервалы, чтобы понять, смогу ли я сегодня записаться к этому врачу?
Сделать нужно в одном SQL-запросе. Без процедур. | |
|
|
|
|
|
|
|
для: webstalk3r
(16.08.2011 в 15:29)
| | Переводите время и интервалы в секунды при помощи функции UNIX_TIMESTAMP() и смотрите есть ли подходящие интервалы при помощи самообъединения таблицы. | |
|
|
|
|
|
|
|
для: cheops
(16.08.2011 в 15:41)
| | Можно пример? Какую таблицу самообъединять? Их тут две. | |
|
|
|
|
|
|
|
для: webstalk3r
(16.08.2011 в 16:00)
| | А можно кусочек дампа этих таблиц, чтобы можно было поэкспериментировать локально? | |
|
|
|
|
|
|
|
для: cheops
(16.08.2011 в 16:02)
| | Пожалуйста, данные из примера:
test_pat - приемы пациентов (тут над форматами можно поспорить, делал для теста. возможно проще к секундам привести)
test_sch - расписание врача
CREATE TABLE IF NOT EXISTS `test_pat` (
`start` float NOT NULL,
`length` int(11) NOT NULL,
PRIMARY KEY (`start`,`length`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO `test_pat` (`start`, `length`) VALUES
(10.15, 45),
(11.3, 30),
(14, 60);
CREATE TABLE IF NOT EXISTS `test_sch` (
`start` int(11) NOT NULL,
`finish` int(11) NOT NULL,
PRIMARY KEY (`start`,`finish`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO `test_sch` (`start`, `finish`) VALUES
(10, 13),
(14, 15),
(16, 20);
|
| |
|
|
|
|
|
|
|
для: webstalk3r
(16.08.2011 в 16:14)
| | С такой таблицей мы долго провозимся, давайте возьмем таблицу, которую вы представили в начале, где используется DATETIME, кроме того, добавим в таблицу начало и конец работы
CREATE TABLE test_pat (
`start` datetime NOT NULL,
length int(11) NOT NULL,
PRIMARY KEY (`start`,length)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO test_pat VALUES('2011-08-17 08:00:00', 0);
INSERT INTO test_pat VALUES('2011-08-17 10:15:00', 45);
INSERT INTO test_pat VALUES('2011-08-17 11:30:00', 30);
INSERT INTO test_pat VALUES('2011-08-17 14:00:00', 60);
INSERT INTO test_pat VALUES('2011-08-17 17:00:00', 0);
| Получить время старта и окончания интервалов работы можно при помощи запроса
SELECT
start,
start + INTERVAL length MINUTE AS end
FROM test_pat
ORDER BY start
| Запрос, вычисляющий свободные интервалы в минутах, может выглядеть следующим образом
SELECT
TIME(fst.start) AS fst_start,
TIME(fst.start + INTERVAL fst.length MINUTE) AS fst_end,
TIME(snd.start) AS snd_start,
TIME(snd.start + INTERVAL snd.length MINUTE) AS snd_end,
MIN(
UNIX_TIMESTAMP(snd.start) -
UNIX_TIMESTAMP(fst.start + INTERVAL fst.length MINUTE)
) / 60 AS free
FROM
test_pat fst
LEFT JOIN
test_pat snd
ON
fst.start < snd.start AND
fst.start + INTERVAL fst.length MINUTE < snd.start
GROUP BY fst.start
| Собственно примерно так и работает самообъединение, вы осуществляете многотабличный запрос к той же самой таблице, смещая записи относительно друг друга. | |
|
|
|
|
|
|
|
для: cheops
(17.08.2011 в 23:40)
| | Спасибо за вариант.
Я пошел с другого конца:
1) получил интервалы когда врач не работает (интервал от 0 часов до min(start) + union + интервалы между перерывами со смещением в 1 строчку + union + интервал от max(finish) до 24);
2) union (1) с записями пациентов (когда врач тоже "не принимает");
3) отсортировал по старту; (получились все временные интервалы, когда врач занят в течении дня)
4) все это во временную таблицу т1;
5) Селект из т1 во вторую временную таблицу т2; (Я был поражен, когда узнал, что в mysql временную таблицу нельзя дважды использовать в одном запросе. При чем это известный баг на протяжении 5 лет! 2 года работал с ораклом и никогда о таких проблемах не слышал)
6) Join т1 и т2 со смещением в одну строчку | |
|
|
|