はじめに
OracleのSQLのアンチパターンとして、メンテナンス性や可読性の悪いSQLと、修正したSQLを問題集形式で紹介します。
対象読者
- SQLのアンチパターンの問題集を使って理解を深めたい方
必要な環境
本稿で扱うSQLは、Oracle 11.2.0.1.0で動作確認しました。他のDBでも応用が可能です。
1. 1対多の集計を行うSQLのアンチパターン1
よく見かける1対多の集計を行うSQLを考えます。サンプルデータと修正対象のSQLと出力結果は下記です。
ShopID | ShopName |
1 | ABCD |
2 | EFGH |
3 | IJKL |
ShopID | Val |
1 | 100 |
3 | 300 |
3 | 900 |
ShopIDごとの、Valの合計を出力します。
select a.ShopID,a.ShopName,sum(nvl(b.Val),0) as sumVal from ShopT a Left Join AmountT b on a.ShopID = b.ShopID group by a.ShopID,a.ShopName order by a.ShopID;
ShopID | ShopName | sumVal |
1 | ABCD | 100 |
2 | EFGH | 0 |
3 | IJKL | 1200 |
上記のSQLでは、AmountTテーブルを使って求める列はsumValという1列のみであることに注目して、シンプルな記述で同じ結果を取得できるSQLに書き直して下さい。
Left Join
による外部結合を行ってから、group by
でグループ化しているため、結構複雑なSQLになってます。相関サブクエリを使って、少しシンプルにしてみます。
修正後のSQLと解説
select ShopID,ShopName, (select nvl(sum(b.Val),0) from AmountT b where b.ShopID = a.ShopID) as sumVal from ShopT a order by ShopID;
修正後のSQLでは、相関サブクエリを使うことによって、全体のfrom
句にはShopTのみを記述すればよくなり、さらにgroup by
によるグループ化も不要になりました。全体のfrom
句にテーブル指定が1つしかないSQLは、たいていの場合において、可読性の高いSQLになります。
Oracleのselect
文の評価順序は、下記ですので、相関サブクエリを使って、(評価順序の1番目の)全体のfrom
句に記述するテーブルの数を減らし、(評価順序の9番目の)select
句に参照先のテーブルを記述するのは、select
文の処理を脳内でイメージしやすくして、SQLの可読性を上げることになります。
1. from句 2. where句 (結合条件) 3. start with句 4. connect by句 5. where句 (行のフィルタ条件) 6. group by句 7. having句 8. model句 9. select句 10. union、minus、intersectなどの集合演算 11. order by句