2010年7月31日(土) 19:32 JST

HOME > i am BEST > 素直なSQL の書き方 - まずは FROM句から -

素直なSQL の書き方 - まずは FROM句から -

  • 2009年5月 8日(金) 01:26 JST
  • 投稿者:
    hidehi

前回をまとめると、

  • SQL の基本のかたちは SELECT ~ FROM ~ WHERE で、
  • まず FROM で検索元となる"データの集合"を指定し、
  • 必要であれば WHERE で検索条件を指定し、
  • SELECT で表示したいカラム(フィールド)を指定する、

という考え方でまず"自然な/素直なSQL "を書いてみましょう、ということになりますね。

RPG 経験者であれば、FROM 句はより自由度の高い F 仕様書(普通 F 仕様書から書き始めますよね)、C 仕様書が WHERE 句やこれからふれていこうと思っているいろいろな SQL の選択/集計機能、SELECT 句で最終的に表示したいカラム(フィールド)を O 仕様書のように選んで指定する、というイメージを持っていただければとっつきやすいのではないでしょうか。

今回は、より具体的に、実際に近いSQL の例を使ってFROM 句の指定のしかた(発想も、実際に書くのもそれが最初になりますから)を見ていきたいと思います。



FROM で指定する"データの集合"は、
一番シンプルなケースではテーブル名、
複数のテーブルから情報を取ってきて組み合わせたい場合は、(そのたいていのケースでは)
"テーブル名 JOIN テーブル名 ON 結合カラム名 = 結合カラム名"になります。

JOIN にはいくつか種類がありますが、それは「SQL書き方ドリル」や「IBM i5/OS 情報」などを見てみてください。

今回は実際のサンプルデータベースなどを使って、どのように役に立つかを見ていきたいと思います。
(ちなみに、サンプルのデータベースは CREATE_SQL_SAMPLE ストアド・プロシージャで作成したものを使用しています。また、例に出てくるすべてのSQL はV5R4/V6R1 の DB2 for IBM i で実行できることを確認しています)

たとえば、
複数のテーブルからデータをとってきたい、という場合、単に名前などの付加情報がほしい、というだけだったりしませんか?

以下のようなフクザツな SQL を例にとって考えてみましょう。

検索元のテーブルは EMPLOYEE ひとつだけです。
部署ID は出てくるのですが、やはり部署名があるとわかりやすいですね。部署名は DEPARTMENT テーブルに存在しています。

もうこの SQL でちゃんとした結果が出てくるのを確認できています。
できれば、この SQL に大きく手を加えず部署名を DEPARTMENT テーブルから取ってきて加えたいところです。

SQL92 以前の古い書きかたであれば、FROM句にカンマで区切ってテーブルを追加して、WHERE 句で結合用のカラムを追加して、とする必要がありました。
今まで存在しなかったWHERE句が追加されるので、データベースのオプティマイザはまったく新しいプランの作り直しになります。
もともとWHERE句が存在していたような場合は、条件が干渉して読みにくくもなりますし、人間に読みにくいということはシステムにとっても解析しにくいことが予想されますね。

FROM 句を差し替えれば、このひとつのテーブルでちゃんとした結果がでる SQL の基本構造を変えなくても、
部署マスターを結合して部署名をとってくることができるんです。

SELECT empno, firstnme, lastname, workdept, salary, 
       RANK() OVER(PARTITION BY workdept ORDER BY salary DESC) RANK,
       DENSE_RANK() OVER(PARTITION BY workdept ORDER BY salary DESC) D_RANK,
       ROW_NUMBER() OVER(PARTITION BY workdept ORDER BY salary DESC) ROW_NUM  
  FROM Sample/Employee                                                 
 ORDER BY workdept, RANK

FROM 句を単一のテーブル名から、結合したテーブルの集合に差し替えます。
各カラムについては、名前が重複したものなどがある可能性がありますから、どのテーブルからのものかをはっきりさせます(E.EMPNO といったように)。
そして、ほしかったカラム(この場合は部署名(D.DEPTNAME)ですね)を追加すればできあがり、です。

SELECT E.empno, E.firstnme, E.lastname, E.workdept, D.deptname, E.salary, 
       RANK() OVER(PARTITION BY E.workdept ORDER BY E.salary DESC) RANK,  
       DENSE_RANK() OVER(PARTITION BY E.workdept ORDER BY E.salary DESC) D_RANK,
       ROW_NUMBER() OVER(PARTITION BY E.workdept ORDER BY E.salary DESC) ROW_NUM  
  FROM (Sample/Employee E JOIN Sample/Department D 
                            ON E.workdept = D.deptno) 
 ORDER BY E.workdept, RANK 

SQL の構造はまったく変わっていないことがわかると思います。

(くりかえしになりますが)
JOIN を使用せず WHERE 句で結合カラムを指定する形だと、本来必要ない余計な WHERE 句をつけることになってしまい、SQL 文の構造が変わってしまいます。
読みにくくもなりますし、極端な場合は結果まで変わってしまうかもしれません。

FROM 句のみの変更であれば、新しい句もなく、全体の骨組みはまったく変わりませんね。
システム(オプティマイザー)にとってもわかりやすい SQL に(通常は)なります。

- JOIN キーワードを使って、
- FROM 句から、
- データの集合はどうなるかを考えながら、
- 最後に SELECT 句でどのテーブルからのカラムかを明確にする、

という順番で考えていけば、
SQL はそれほど難しいものではありません。

ぜひ「古い書きかた」ではなく、"JOIN"  を使うようにしましょう。

ちなみに、↑ の SQL は http://www.geocities.jp/mickindex/database/db_gb_pb.html を参考に作ってみました。

トラックバック

このエントリのトラックバックURL:
http://www.iforum.ne.jp/trackback.php/20090508012607723
表示形式
コメント投稿

コメントは投稿者の責任においてなされるものであり,サイト管理者は責任を負いません。

iForumサポーター

      iFourmの趣旨にご賛同いただき、ご支援いただける企業または個人を募集しています。詳しくは、info@iforum.ne.jp へお願いします。