読者です 読者をやめる 読者になる 読者になる

DPCデータの分析とかやるブログ

DPCデータの分析なんかをテキトーにやってます。

SQL方言について(ついでにDPCチェッカーにクエリを追加)

SQLの方言

残念なことですが、SQLは実装ごとに方言があります。
私はPostgreSQLばっかりいじってたので気にも留めていませんでしたが、今回DPCチェッカーを作っていて否が応でも気付かざる得ませんでした。
DPCチェッカーは組み込みで配布するため、SQLite3を使っています。exe単体で実行できるSQLで、Pythonには何とビルトインされています。
こちらの実装はPostgreSQLとかなり違っていて、例えば日付データをネイティブで扱うことが出来ません。
そこにさえ目をつむれば、大抵のクエリは走るのですが、今回はここで詰まりました。

select データ識別番号,実施年月日,診療明細名称,SUM(明細点数・金額*行為回数) 
from etable
Where データ区分 = 60 
AND (データ識別番号,実施年月日) IN (select データ識別番号,実施年月日 from dtable Where データ区分 = 93) 
group by データ識別番号,実施年月日,診療明細名称
HAVING SUM(明細点数・金額*行為回数) > 0;

以前このブログで紹介した、DPC期間中に行った検査を探すクエリです。 INを使った相関サブクエリで、「Dファイル上でDPC入院料を算定した患者と日付」に条件に絞る、ということをやっています。
このクエリはPostgresでは走りますが、SQLiteでは走りません。 AND (データ識別番号,実施年月日) IN...の部分が問題です。
これをAND データ識別番号 IN...とすると走ります(これでは条件を満たしませんが)。
()でカラムを複数指定するやり方は、行値式というそうで、実装されているSQLは限られています。 (メジャーどころでは、MicrosoftSQL Serverも対応していないとか)
どんなに頭を悩ましたところで、実装されていないものは走りません。書き方を変えます。

select e.データ識別番号,e.実施年月日,e.診療明細名称,SUM(明細点数・金額*行為回数) 
from etable AS e
Where データ区分 = 60 
AND EXISTS (select d.データ識別番号,d.実施年月日 from dtable Where データ区分 = 93
AND dtable.データ識別番号 = etable.データ識別番号
AND dtable.実施年月日 = etable.実施年月日)
group by e.データ識別番号,e.実施年月日,e.診療明細名称
HAVING SUM(明細点数・金額*行為回数) > 0;

今度はEXISTSを使いました。意味合いは違いますが、求める結果は同じです。
Postgresでは走りますので、意気揚々とSQLiteで走らせると・・・答えが返ってきません。
どうやら私がやっつけで書いたクエリに問題があって、Postgresが優しく(見えないところで)始末をつけてくれたのでしょうか。それとも、SQLiteのEXISTS実装にパフォーマンスの問題があるのでしょうか。または、その両方?
前者である可能性が高いですね。 さて困りました。もうちょっとEXISTSについて調べてもいいのですが、手っ取り早いのは以下のクエリです。

WITH d93 AS (select データ識別番号,実施年月日 from dtable Where データ区分 = 93),
e60 AS (select データ識別番号,実施年月日,診療明細名称,SUM(明細点数・金額*行為回数)  AS 出来高金額
from etable
Where データ区分 = 60 
group by データ識別番号,実施年月日,診療明細名称
HAVING SUM(明細点数・金額*行為回数) > 0)
select d93.データ識別番号,d93.実施年月日,e60.診療明細名称,e60.出来高金額
from d93
INNER JOIN e60
USING(データ識別番号,実施年月日);

WITH句でテーブルを2つ作ってINNER JOINでくっつけています。
結局、今回やりたいのは「検査を行った患者とその日付」の集合と、「DPC入院料を算定した患者とその日付」の積を求めること、つまり二つの集合の共通集合を導き出すことです。
ならばINNER JOINで良いわけですね。

(ちなみに、上記のクエリは検査版と注射版を作って、DPCチェッカーに追加しておきました)