2017-02-12 18 views
2

私は医療データを扱っており、特定の患者に一次診断を与えたいと思っています。PostgreSQLの値リストに一致する文字列の最初の部分を選択する方法は?

診断はすべて1つの列にカンマ区切りの文字列として表示されます。たとえば、「A10.3、B55.2、A10.1」となります。この表患者と診断diag_listの列を呼び出します。 diag_listの最初の部分を含む新しい列を作成し、別のテーブルに一致するものがあります。このテーブルには、「プライマリ」と考えられる診断リストが含まれています。このテーブルをICD10と呼び、プライマリ診断のリストをprimary_diagとしています。

私が最初の試合をしたい理由は、diag_listはすでに症状の重症度に従ってソートされているからです。だから、私は一次診断と見なすことができる最も重症の症状で診断を見つけることを試みています。

最初にdiag_listをstring_to_arrayの配列に変換しようとしましたが、この新しい配列から最初に一致する文字列を条件付きで選択する方法が見つかりませんでした。あなたはこれをどのように選択しますか?あるいは、より単純でより効率的な同じ結論に達するための全く異なる方法がいくつかありますか?

+1

要求された結果を含むいくつかのデータサンプルを追加してください。 –

答えて

2

string_to_arrayを取得したら、unnestにする必要があります。その後、ICD10に参加する必要があり、患者ごとにfirstという診断を受けます。

は、我々は次のようなデータがあるとします。

SELECT 
    patient_id, trim(diag) AS diag, nr 
FROM 
    patients 
    JOIN LATERAL unnest(string_to_array(diag_list, ',')) 
     WITH ORDINALITY AS a(diag, nr) ON true ; 

+------------+-------+----+ 
| patient_id | diag | nr | 
+------------+-------+----+ 
|   1 | A10.3 | 1 | 
|   1 | B55.2 | 2 | 
|   1 | A10.1 | 3 | 
|   2 | A10.3 | 1 | 
|   2 | A10.1 | 2 | 
|   2 | C20.2 | 3 | 
+------------+-------+----+ 

次のステップを取得:このデータでは

CREATE TABLE patients 
(
    patient_id integer PRIMARY KEY, 
    diag_list text NOT NULL 
) ; 

INSERT INTO patients 
VALUES 
    (1, 'A10.3,B55.2, A10.1') , 
    (2, 'A10.3, A10.1, C20.2') ; 

CREATE TABLE ICD10 
(
    primary_diag text PRIMARY KEY, 
    diagnose text 
) ; 

INSERT INTO ICD10 
VALUES 
    ('B55.2', 'Something Bad'), 
    ('A10.1', 'Somehitng Worse'); 

を、我々はunnest with ordinalityあなたのデータに開始することができます参加しますこのデータはICD10付き

WITH patients_and_diags AS 
(
SELECT 
    patient_id, trim(diag) AS diag, nr 
FROM 
    patients 
    JOIN LATERAL unnest(string_to_array(diag_list, ',')) 
     WITH ORDINALITY AS a(diag, nr) ON true 
) 
SELECT 
    patient_id, diag, nr, diagnose 
FROM 
    patients_and_diags 
    JOIN ICD10 ON ICD10.primary_diag = patients_and_diags.diag ; 
...とget:

+------------+-------+----+-----------------+ 
| patient_id | diag | nr | diagnose  | 
+------------+-------+----+-----------------+ 
|   1 | B55.2 | 2 | Something Bad | 
|   1 | A10.1 | 3 | Somehitng Worse | 
|   2 | A10.1 | 2 | Somehitng Worse | 
+------------+-------+----+-----------------+ 

は、今、私たちは、それぞれが

次のクエリをpatient_idのみ最小NR '' を取る必要はワンステップですべてを行い

WITH patients_and_diags AS 
(
SELECT 
    patient_id, trim(diag) AS diag, nr 
FROM 
    patients 
    JOIN LATERAL unnest(string_to_array(diag_list, ',')) 
     WITH ORDINALITY AS a(diag, nr) ON true 
) 
, patients_and_ICD10 AS 
(
SELECT 
    patient_id, diag, nr, diagnose 
FROM 
    patients_and_diags 
    JOIN ICD10 ON ICD10.primary_diag = patients_and_diags.diag 
) 
, first_ICD10 AS 
(
SELECT 
    patient_id, min(nr) AS nr 
FROM 
    patients_and_ICD10 
GROUP BY 
    patient_id 
) 
SELECT 
    patient_id, diag, diagnose 
FROM 
    first_ICD10 
    JOIN patients_and_ICD10 USING(patient_id, nr) ; 

...そしてあなたを得る:

+------------+-------+-----------------+ 
| patient_id | diag | diagnose  | 
+------------+-------+-----------------+ 
|   1 | B55.2 | Something Bad | 
|   2 | A10.1 | Somehitng Worse | 
+------------+-------+-----------------+ 

をクエリは、いくつかのWINDOWの機能を使用することによって短くすることができhttp://rextester.com/RDYPD23700

にすべてをチェックすることができます。私はこの段階的なアプローチがより明確だと思います。

+0

素敵な答え。私は 'min(nr)'がウィンドウ関数でうまくいっていると思う。rextester.comについてよくわからない、sqlfiddleよりもはるかに速く見える! – Andomar

+0

@Andomar:おそらく 'first_value() (そしてあまりにも多くのコンセプト)を常にベストプラクティスとしているのかどうかは不明だが、「早期に最適化しない」(http: //wiki.c2.com/?PrematureOptimization);-) – joanolo

+0

ありがとうございました!これは私の問題を解決し、あなたの説明はとても読みやすいものでした。私は 'w私は現在取り扱っているデータで複数の状況で便利になるでしょう。 –

1

これは扱いにくいです。 Postgres 9.4以降、unnest()のキーワードはwith ordinalityです。これには、ポジション列が含まれます。これは、いくつかの他のものとの組み合わせで、何が必要でしょう。

select distinct on (p.patientid) p.*, d.* 
from patients p, later 
    unnest(string_to_array(p.diag_list, ',')) with ordinality dp(code, ord) join 
    diagnoses d 
    on d.code = dp.code 
order by p.patientid, ord asc; 

驚くことではないが、アーウィンBrandstetterは、この問題のdiscussionを持ち、どのようにそれを解決するために。

+0

残念ながら、 "最初のもの"は条件付きです: "異なるテーブルに一致するdiag_listの最初の部分" – Andomar

+0

@Andomar ...。 –

0

unnest"normalize"診断を使用することができます。つまり、患者と診断の組み合わせごとに1つの行があることを意味します。 generate_subscriptsを使用して、その診断の位置をリストに追加します。 (他の回答で提案されているようにはPostgres 9.4以降では、with ordinalityは、良いです。)あなたはdiagnisticsを注文する位置を使用して、リスト内で最高の主要な診断のためにフィルタリングすることができます:ここで

with normal_pat as 
     (
     select name 
     ,  unnest(string_to_array(diag_list, ',')) as diag 
     ,  generate_subscripts(string_to_array(diag_list, ','),1) as pos 
     from patients 
     ) 
,  numbered_pat as 
     (
     select row_number() over (partition by name order by pos) rn 
     ,  * 
     from normal_pat 
     join diagnostics d 
     on  normal_pat.diag = d.primary_diag 
     ) 
select name 
,  diag 
,  pos as position_of_diagnostic_in_list 
from numbered_pat 
where rn = 1 

があります作業例はSQL Fiddleまたはrextesterです。

関連する問題