Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
C++. Мастер-класс в задачах и примерах. Авторы: Кузнецов М.В., Симдянов И.В. Самоучитель PHP 5 / 6 (3 издание). Авторы: Кузнецов М.В., Симдянов И.В. Социальная инженерия и социальные хакеры. Авторы: Кузнецов М.В., Симдянов И.В. PHP 5/6. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В. PHP Puzzles. Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум MySQL

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Вычитание временных интервалов друг из друга
 
 автор: webstalk3r   (16.08.2011 в 15:29)   письмо автору
 
 

Добрый день.
Задача следующая:

Есть расписание работы врача в виде часовых временных интервалов:
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-запросе. Без процедур.

  Ответить  
 
 автор: cheops   (16.08.2011 в 15:41)   письмо автору
 
   для: webstalk3r   (16.08.2011 в 15:29)
 

Переводите время и интервалы в секунды при помощи функции UNIX_TIMESTAMP() и смотрите есть ли подходящие интервалы при помощи самообъединения таблицы.

  Ответить  
 
 автор: webstalk3r   (16.08.2011 в 16:00)   письмо автору
 
   для: cheops   (16.08.2011 в 15:41)
 

Можно пример? Какую таблицу самообъединять? Их тут две.

  Ответить  
 
 автор: cheops   (16.08.2011 в 16:02)   письмо автору
 
   для: webstalk3r   (16.08.2011 в 16:00)
 

А можно кусочек дампа этих таблиц, чтобы можно было поэкспериментировать локально?

  Ответить  
 
 автор: webstalk3r   (16.08.2011 в 16:14)   письмо автору
 
   для: 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);

  Ответить  
 
 автор: cheops   (17.08.2011 в 23:40)   письмо автору
 
   для: 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
Собственно примерно так и работает самообъединение, вы осуществляете многотабличный запрос к той же самой таблице, смещая записи относительно друг друга.

  Ответить  
 
 автор: webstalk3r   (18.08.2011 в 17:13)   письмо автору
 
   для: 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 со смещением в одну строчку

  Ответить  
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования