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は限られています。
(メジャーどころでは、MicrosoftのSQL 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チェッカーに追加しておきました)