SQLのUNIONをORにして保守性やパフォーマンスを向上させる
はじめに
今回の記事では、SQLのUNIONをORにしてみます。保守性(改修時に手を入れる箇所が少なくて済む)や可読性が向上して、パフォーマンスもよくなる可能性が高いので、条件が合えば試してみてください。
具体例
以下のSQLを例に挙げます。
シチュエーションとしては、同一顧客がすでに本登録されているかチェックするイメージです。個人の場合は「カナ+生年月日」で、法人の場合は「カナ」だけで名寄せします。
UNION(ALL)の場合
UNION(ALL)の上側が個人のブロックで、下側が法人のブロックです。
(重複行をまとめる必要がない場合は「UNION」ではなく「UNION ALL」にしましょう。無駄にsortとuniqueがされないように。)
SELECT 顧客.ID, 顧客.氏名漢字 FROM 顧客 WHERE 顧客.登録状況 = '本登録' AND 顧客.個人法人区分 = '個人' AND 顧客.個人法人区分 = 引数.個人法人区分 AND 顧客.氏名カナ = 引数.氏名カナ AND 顧客.生年月日 = 引数.生年月日 UNION ALL SELECT 顧客.ID, 顧客.氏名漢字 FROM 顧客 WHERE 顧客.登録状況 = '本登録' AND 顧客.個人法人区分 = '法人' AND 顧客.個人法人区分 = 引数.個人法人区分 AND 顧客.氏名カナ = 引数.氏名カナ ;
ORの場合
上記をORで書き直したものが以下のSQLです。
SELECT句の項目やWHERE句の共通的な条件が1箇所にまとまって保守性がUPし、差異がある個人と法人の部分も浮き出てきて可読性もUPしているように思います。
(氏名カナのAND条件は共通化(個人法人区分の直後に外出し)してもいいかもです。)
SELECT 顧客.ID, 顧客.氏名漢字 FROM 顧客 WHERE 顧客.登録状況 = '本登録' AND 顧客.個人法人区分 = 引数.個人法人区分 AND ( ( 顧客.個人法人区分 = '個人' AND 顧客.氏名カナ = 引数.氏名カナ AND 顧客.生年月日 = 引数.生年月日 ) OR ( 顧客.個人法人区分 = '法人' AND 顧客.氏名カナ = 引数.氏名カナ ) ) ;
ただ、ORにするにはいくつか条件もありそうです。
- UNIONの上下のクエリのFROM句が、同じテーブルであること(上記の例だとどちらも「顧客」テーブル)
- UNIONの上下のクエリで、各々何らかの結果(レコード)をとりたい場合は使えない
また実際のパフォーマンスは、テーブル構造やインデックス、統計情報等により変わってくると思いますので、実行計画を確認しながらやってみてください。