pma*_*v99 11 mysql innodb mysql-5.5
代码将在 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;
Run Code Online (Sandbox Code Playgroud)
这张表是关于医院里的病人的,它存储了每个病人在住院期间花费了一段时间的床位。
每个病房可能有多张病床,每个病人可能会搬到同一个病房内的不同病床。
我想要做的是找出每位患者在没有搬到不同病房的情况下在特定病房中度过的时间。即我想找到他在同一病房内连续逗留的总时间。
-- 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);
Run Code Online (Sandbox Code Playgroud)
在实际表中,行不是连续的,但对于每个患者,一行的出院时间戳 == 下一行的入院时间戳。
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);
Run Code Online (Sandbox Code Playgroud)
请注意,我们不能按患者 ID 分组。我们必须为每次 ICU 访问检索单独的记录。
说得更通俗一点,如果一个病人在ICU呆了一段时间,然后搬出来又回到那里,我需要检索他在每次ICU访问中花费的总时间(即两个记录)
查询 1,在SQLFiddle-1中测试
SET @ward_id_to_check = 1 ;
SELECT
st.patient_id,
st.bed_id AS starting_bed_id, -- the first bed a patient uses
-- can be omitted
st.admitted,
MIN(en.discharged) AS discharged
FROM
( SELECT patient_id, bed_id, admitted, discharged
FROM t
WHERE t.ward_id = @ward_id_to_check
AND NOT EXISTS
( SELECT *
FROM t AS prev
WHERE prev.ward_id = @ward_id_to_check
AND prev.patient_id = t.patient_id
AND prev.discharged = t.admitted
)
) AS st
JOIN
( SELECT patient_id, admitted, discharged
FROM t
WHERE t.ward_id = @ward_id_to_check
AND NOT EXISTS
( SELECT *
FROM t AS next
WHERE next.ward_id = @ward_id_to_check
AND next.patient_id = t.patient_id
AND next.admitted = t.discharged
)
) AS en
ON st.patient_id = en.patient_id
AND st.admitted <= en.admitted
GROUP BY
st.patient_id,
st.admitted ;
Run Code Online (Sandbox Code Playgroud)
查询2,与1相同,但没有派生表。这可能会有更好的执行计划和适当的索引。在SQLFiddle-2中测试:
SET @ward_id_to_check = 1 ;
SELECT
st.patient_id,
st.bed_id AS starting_bed_id,
st.admitted,
MIN(en.discharged) AS discharged
FROM
t AS st -- starting period
JOIN
t AS en -- ending period
ON en.ward_id = @ward_id_to_check
AND st.patient_id = en.patient_id
AND NOT EXISTS
( SELECT *
FROM t AS next
WHERE next.ward_id = @ward_id_to_check
AND next.patient_id = en.patient_id
AND next.admitted = en.discharged
)
AND st.admitted <= en.admitted
WHERE
st.ward_id = @ward_id_to_check
AND NOT EXISTS
( SELECT *
FROM t AS prev
WHERE prev.ward_id = @ward_id_to_check
AND prev.patient_id = st.patient_id
AND prev.discharged = st.admitted
)
GROUP BY
st.patient_id,
st.admitted ;
Run Code Online (Sandbox Code Playgroud)
这两个查询都假设 存在唯一约束(patient_id, admitted)
。如果服务器以严格的 ANSI 设置运行,bed_id
则应将其添加到GROUP BY
列表中。
归档时间: |
|
查看次数: |
1686 次 |
最近记录: |