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`

今、クエリを使用して各患者の 2 回目の最後の訪問をフェッチしたいのですが、エラーが発生します (#1242 - サブクエリが複数の行を返します)

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は最後の訪問のID、は最後id2から2番目の訪問のIDです。

于 2012-12-24T08:20:25.327 に答える
2

最初のクエリでは、結果が 2 と 9 ではなく 5 と 6 になるため、最後の訪問を取得できません。次のクエリを試すことができます。

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

指定された結果セットを単一のSQLステートメントで返すには、いくつかの方法があります。

残念ながら、これらのアプローチのほとんどは、かなり扱いにくいステートメントを生成します。

よりエレガントに見えるステートメントは、大きなセットを扱うときにパフォーマンスが低下する(または耐えられない)傾向があります。また、パフォーマンスが向上する傾向のあるステートメントは、よりエレガントに見えません。

最も一般的なアプローチの3つは以下を利用します:

  • 相関サブクエリ
  • 不等式結合(ほぼデカルト積)
  • データを2回渡す

これは、MySQLユーザー変数を使用してデータを2回パスするアプローチです。これは、基本的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

これにはインラインビューが含まれることに注意してください。つまり、「派生テーブル」を作成するためにテーブル内のすべてのデータが渡されます。次に、外部クエリが派生テーブルに対して実行されます。したがって、これは基本的にデータの2回のパスです。

patient_idこのクエリは、インラインビューによって返される列の重複する値を削除することにより、パフォーマンスを向上させるために少し調整できます。しかし、私はそれを上記のように示しているので、何が起こっているのかをよりよく理解することができます。

このアプローチは、大規模なセットではかなり高価になる可能性がありますが、一般に、他のいくつかのアプローチよりもはるかに効率的です。

また、その患者の値がpatient_id1つしかない場合、このクエリはaの行を返すことにも注意してください。id少なくとも2行ある患者だけに戻ることを制限するものではありません。


相関サブクエリを使用して同等の結果セットを取得することもできます。

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のオーダーで巨大になる可能性があります。

于 2012-12-24T08:51:23.833 に答える
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 に答える
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 に答える