Версия MySQL
Код будет работать в MySQL 5.5
Фон
У меня есть таблица, подобная следующей
CREATE TABLE t
( id INT NOT NULL AUTO_INCREMENT
, patient_id INT NOT NULL
, bed_id INT NOT NULL
, ward_id INT NOT NULL
, admitted DATETIME NOT NULL
, discharged DATETIME
, PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
Эта таблица о пациентах в больнице и хранит кровати, где каждый пациент провел некоторое время, находясь в больнице.
В каждой палате может быть несколько кроватей, и каждый пациент может перейти на другую кровать в одной и той же палате.
Задача
Я хочу выяснить, сколько времени каждый пациент провел в определенном отделении, не переходя в другое отделение. Т.е. я хочу узнать общую продолжительность последовательного времени, которое он провел в одной и той же палате.
Прецедент
-- Let's assume that ward_id = 1 corresponds to ICU (Intensive Care Unit)
INSERT INTO t
(patient_id, bed_id, ward_id, admitted, discharged)
VALUES
-- Patient 1 is in ICU, changes some beds, then he is moved
-- out of ICU, back in and finally he is out.
(1, 1, 1, '2015-01-06 06:05:00', '2015-01-07 06:04:00'),
(1, 2, 1, '2015-01-07 06:04:00', '2015-01-07 07:08:00'),
(1, 1, 1, '2015-01-07 07:08:00', '2015-01-08 08:11:00'),
(1, 4, 2, '2015-01-08 08:11:00', '2015-01-08 09:11:00'),
(1, 1, 1, '2015-01-08 09:11:00', '2015-01-08 10:11:00'),
(1, 3, 1, '2015-01-08 10:11:00', '2015-01-08 11:11:00'),
(1, 1, 2, '2015-01-08 11:11:00', '2015-01-08 12:11:00'),
-- Patient 2 is out of ICU, he gets inserted in ICU,
-- changes some beds and he is back out
(2, 1, 2, '2015-01-06 06:00:00', '2015-01-07 06:04:00'),
(2, 1, 1, '2015-01-07 06:04:00', '2015-01-07 07:08:00'),
(2, 3, 1, '2015-01-07 07:08:00', '2015-01-08 08:11:00'),
(2, 1, 2, '2015-01-08 08:11:00', '2015-01-08 09:11:00'),
-- Patient 3 is not inserted in ICU
(3, 1, 2, '2015-01-08 08:10:00', '2015-01-09 09:00:00'),
(3, 2, 2, '2015-01-09 09:00:00', '2015-01-10 10:01:00'),
(3, 3, 2, '2015-01-10 10:01:00', '2015-01-11 12:34:00'),
(3, 4, 2, '2015-01-11 12:34:00', NULL),
-- Patient 4 is out of ICU, he gets inserted in ICU without changing any beds
-- and goes back out.
(4, 1, 2, '2015-01-06 06:00:00', '2015-01-07 06:04:00'),
(4, 2, 1, '2015-01-07 06:04:00', '2015-01-07 07:08:00'),
(4, 1, 2, '2015-01-07 07:08:00', '2015-01-08 09:11:00'),
-- Patient 5 is out of ICU, he gets inserted in ICU without changing any beds
-- and he gets dismissed.
(5, 1, 2, '2015-01-06 06:00:00', '2015-01-07 06:04:00'),
(5, 3, 2, '2015-01-07 06:04:00', '2015-01-07 07:08:00'),
(5, 1, 1, '2015-01-07 07:08:00', '2015-01-08 09:11:00'),
-- Patient 6 is inserted in ICU and he is still there
(6, 1, 1, '2015-01-11 12:34:00', NULL);
В реальной таблице строки не являются последовательными, но для каждого пациента отметка времени выписки из одной строки == отметка времени приема следующей строки.
SQLFiddle
http://sqlfiddle.com/#!2/b5fe5
ожидаемый результат
Я хотел бы написать что-то вроде следующего:
SELECT pid, ward_id, admitted, discharged
FROM (....)
WHERE ward_id = 1;
(1, 1, '2015-01-06 06:05:00', '2015-01-08 08:11:00'),
(1, 1, '2015-01-08 09:11:00', '2015-01-09 11:11:00'),
(2, 1, '2015-01-07 06:04:00', '2015-01-08 08:11:00'),
(4, 1, '2015-01-07 06:04:00', '2015-01-07 07:08:00'),
(5, 1, '2015-01-07 07:08:00', '2015-01-08 09:11:00'),
(6, 1, '2015-01-11 12:34:00', NULL);
Пожалуйста, обратите внимание, что мы не можем группировать по Patient_id. Мы должны получить отдельную запись для каждого посещения отделения интенсивной терапии.
Проще говоря, если пациент проводит время в отделении интенсивной терапии, затем выходит из него и затем возвращается туда, мне нужно получить общее время, которое он провел за каждое посещение отделения интенсивной терапии (то есть две записи)
Ответы:
Запрос 1, протестирован в SQLFiddle-1
Запрос 2, такой же, как 1, но без производных таблиц. Это, вероятно, будет иметь лучший план выполнения с надлежащими индексами. Тест в SQLFiddle-2 :
Оба запроса предполагают наличие уникального ограничения
(patient_id, admitted)
. Если сервер работает со строгими настройками ANSI, егоbed_id
следует добавить вGROUP BY
список.источник
ПРЕДЛАГАЕМЫЙ ЗАПРОС
Я загрузил ваши образцы данных в локальную базу данных на моем ноутбуке. Затем я запустил запрос
ПРЕДЛАГАЕМЫЙ ЗАПРОС ИСПОЛНЕНО
ПРЕДЛАГАЕМЫЙ ЗАПРОС ОБЪЯСНЕН
В подзапросе AA я вычисляю количество прошедших секунд, используя UNIX_TIMESTAMP () , вычитая
UNIX_TIMESTAMP(discharged)
FROMUNIX_TIMESTAMP(admitted)
. Если пациент все еще лежит в кровати (как указано разряженным существомNULL
), я назначаю текущее время СЕЙЧАС () . Затем я делаю вычитание. Это даст вам самую последнюю продолжительность для любого пациента, который все еще находится в палате.Затем я собираю сумму секунд по
patient_id
. Наконец, я беру секунды для каждого пациента и использую SEC_TO_TIME () для отображения часов, минут и секунд пребывания пациента.Дайте ему попробовать!
источник
A
иAA
). Я думаю, что одного из них достаточно.