エンジニアのはしくれ

システム開発、ものづくり、etc…

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の上下のクエリで、各々何らかの結果(レコード)をとりたい場合は使えない

また実際のパフォーマンスは、テーブル構造やインデックス、統計情報等により変わってくると思いますので、実行計画を確認しながらやってみてください。