0

我有一张桌子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`

我错在哪里

4

6 回答 6

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是最后一次访问id2的 ID,是倒数第二次访问的 ID。

于 2012-12-24T08:20:25.327 回答
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
于 2012-12-24T08:28:13.743 回答
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`
于 2012-12-24T08:18:13.010 回答
1

有几种方法可以在单个 SQL 语句中返回指定的结果集。

不幸的是,这些方法中的大多数都会产生相当笨拙的语句。

在处理大型集合时,看起来更优雅的语句往往表现不佳(或无法忍受)。往往具有更好性能的语句看起来更不优雅。

三种最常见的方法使用:

  • 相关子查询
  • 不等式连接(几乎是笛卡尔积)
  • 两次遍历数据

这是一种使用 MySQL 用户变量对数据进行两次传递的方法,它基本上模拟了RANK() OVER(PARTITION ...)其他 DBMS 中可用的分析函数:


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存在一个值,则此查询将为 a 返回一行;它不仅限于返回至少有两排的患者。


也可以使用相关的子查询获得等效的结果集:

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每个患者的值相对较少,则可以使用不等式 join来解决:

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。

于 2012-12-24T08:51:23.833 回答
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
于 2012-12-24T08:24:15.903 回答
-1

为什么不简单地使用...

GROUP BY `patient_ID` DESC LIMIT 2

...然后在下一步中完成其余的工作?

于 2012-12-24T08:08:07.313 回答