我有一张表tbl_patient
,我希望获取每位患者的最后2次访问,以便比较患者病情是在改善还是有所降低。
tbl_patient
id | patient_ID | visit_ID | patient_result
1 | 1 | 1 | 5
2 | 2 | 1 | 6
3 | 2 | 3 | 7
4 | 1 | 2 | 3
5 | 2 | 3 | 2
6 | 1 | 3 | 9
我尝试了下面的查询来获取每位患者的最后一次就诊,
SELECT MAX(id), patient_result FROM `tbl_patient` GROUP BY `patient_ID`
现在我想通过查询获取每位患者的第二次访问,但它给了我错误 (#1242 - 子查询返回超过1行)
SELECT id, patient_result FROM `tbl_patient` WHERE id <(SELECT MAX(id) FROM `tbl_patient` GROUP BY `patient_ID`) GROUP BY `patient_ID`
我错了
答案 0 :(得分:4)
select p1.patient_id, p2.maxid id1, max(p1.id) id2
from tbl_patient p1
join (select patient_id, max(id) maxid
from tbl_patient
group by patient_id) p2
on p1.patient_id = p2.patient_id and p1.id < p2.maxid
group by p1.patient_id
id11
是上次访问的ID,id2
是第二次访问的ID。
答案 1 :(得分:2)
您的第一个查询未获得最后一次访问,因为它提供结果5和6而不是2和9。 您可以尝试此查询:
SELECT patient_ID,visit_ID,patient_result
FROM tbl_patient
where id in (
select max(id)
from tbl_patient
GROUP BY patient_ID)
union
SELECT patient_ID,visit_ID,patient_result
FROM tbl_patient
where id in (
select max(id)
from tbl_patient
where id not in (
select max(id)
from tbl_patient
GROUP BY patient_ID)
GROUP BY patient_ID)
order by 1,2
答案 2 :(得分:1)
SELECT id, patient_result FROM `tbl_patient` t1
JOIN (SELECT MAX(id) as max, patient_ID FROM `tbl_patient` GROUP BY `patient_ID`) t2
ON t1.patient_ID = t2.patient_ID
WHERE id <max GROUP BY t1.`patient_ID`
答案 3 :(得分:1)
有几种方法可以在单个SQL语句中返回指定的结果集。
不幸的是,大多数这些方法都会产生相当笨拙的陈述。
在处理大型集合时,更优雅的语句往往会带来较差(或无法忍受)的性能。而往往具有更好性能的陈述看起来更不优雅。
最常见的三种方法可以使用:
这是一种使用MySQL用户变量对数据使用两次传递的方法,它基本上模拟了其他DBMS中可用的分析RANK() OVER(PARTITION ...)
函数:
SELECT t.id
, t.patient_id
, t.visit_id
, t.patient_result
FROM (
SELECT p.id
, p.patient_id
, p.visit_id
, p.patient_result
, @rn := if(@prev_patient_id = patient_id, @rn + 1, 1) AS rn
, @prev_patient_id := patient_id AS prev_patient_id
FROM tbl_patients p
JOIN (SELECT @rn := 0, @prev_patient_id := NULL) i
ORDER BY p.patient_id DESC, p.id DESC
) t
WHERE t.rn <= 2
请注意,这涉及内联视图,这意味着将对表中的所有数据进行传递以创建“派生表”。然后,外部查询将针对派生表运行。所以,这基本上是对数据的两次传递。
通过消除内联视图返回的patient_id
列的重复值,可以稍微调整此查询以提高性能。但我如上所示,所以我们可以更好地了解正在发生的事情。
这种方法在大型集合上可能相当昂贵,但通常比其他一些方法更有效。
另请注意,如果该患者只存在一个patient_id
值,则此查询将返回id
的行;它不会将回报限制在那些至少有两排的患者身上。
也可以使用相关子查询获得等效的结果集:
SELECT t.id
, t.patient_id
, t.visit_id
, t.patient_result
FROM tbl_patients t
WHERE ( SELECT COUNT(1) AS cnt
FROM tbl_patients p
WHERE p.patient_id = t.patient_id
AND p.id >= t.id
) <= 2
ORDER BY t.patient_id ASC, t.id ASC
请注意,这是使用“依赖子查询”,这基本上意味着对于从t
返回的每一行,MySQL实际上是针对数据库运行另一个查询。因此,对于大型集合来说,这将非常昂贵(就经过的时间而言)。
另一种方法是,如果每位患者的id
值相对较少,您可以通过不平等加入来实现:
SELECT t.id
, t.patient_id
, t.visit_id
, t.patient_result
FROM tbl_patients t
LEFT
JOIN tbl_patients p
ON p.patient_id = t.patient_id
AND t.id < p.id
GROUP
BY t.id
, t.patient_id
, t.visit_id
, t.patient_result
HAVING COUNT(1) <= 2
请注意,这将为每位患者创建近乎笛卡尔的产品。对于每位患者的有限数量id
值,这不会太糟糕。但如果患者有数百id
个值,则中间结果可能很大,大约为(O)n ** 2.
答案 4 :(得分:0)
试试这个..
SELECT id, patient_result FROM tbl_patient AS tp WHERE id < ((SELECT MAX(id) FROM tbl_patient AS tp_max WHERE tp_max.patient_ID = tp.patient_ID) - 1) GROUP BY patient_ID
答案 5 :(得分:-1)
为什么不简单地使用......
GROUP BY `patient_ID` DESC LIMIT 2
......并在下一步中完成其余的工作?