株式会社ジーワンシステムの代表取締役。 新しいものを生み出して世の中をあっといわせたい。イノベーションってやつ起こせたらいいな。

【SQL講座3】サブクエリについて

»

 今回は、サブクエリについてです。

 基本的にサブクエリには書く場所によって、

  • SELECT句
  • FROM句
  • WHERE(HAVING)句

の3種類があります。

 最近は、Accessのシステムをやることはなくなったので詳しくないのですが、AccessのSQLではFROM句、SELECT句には書けなかったり、他のDBMSでもバージョンによってできないことがあります。

 それぞれ、書く場所によって特徴があります。

■ SELECT句(基本的にサブクエリの結果がスカラであること)

 サブクエリ内のWHERE(HAVING)句で、親にあたるFROM句にあるテーブル・ビュー・サブクエリ・テーブルファンクションのカラムを参照することができます。

 親にあたるSQL文の出力結果の件数と同じ回数実行され、その結果は必ず1件でなければいけません。

■ FROM句(サブクエリの結果がほかの句で利用されるとき)

 親にあたるカラムを一切参照することはできません。

 独立したSQLとして実行できる必要があり、1度しか実行されません(つまり、WHERE句の条件はリテラルでなければなりません)。

 JOIN の仕方によって、最終の出力データが増えることも減ることもあります。出力結果はメモリー上に展開され、JOINに元のインデックスが使われることはありません。

■ WHERE(HAVING)句(絞込み条件のためのサブクエリ)

 ※ わたしはHAVING句で使ったことはないけど、文法的には使える。

 サブクエリ内のWHERE(HAVING)句で、親にあたるFROM句にあるテーブル・ビュー・サブクエリ・テーブルファンクションのカラムを参照することができます。

 サブクエリの件数に関わらず、最終出力結果は減ることはあっても増えることはありません。

◇ IN述語のとき

 基本的にサブクエリを親のFROM句より先に実行します。サブクエリの結果の数だけ、OR と同様に評価します。

◇ EXISTS述語のとき

 基本的にサブクエリを親のFROM句の後で実行します。親のFROM句ので抽出されたデータと一致するサブクエリの結果が、1件でもあればそれ以上は評価しません。

 意味を書けばこれだけのことです。

 ネストして使われることがあるのはFROM句で、括弧の内側から順に実行されます。結果はメモリ上にすべて展開され、元のインデックスを使われることはないため、内側のサブクエリで十分な絞込みを行っていないとパフォーマンスは非常に悪くなります。

 一番外側のWHERE句に正しい絞込み条件を書けば、結果は同じになりますけれど、要するに、外側のWHERE句で絞り込めばそれだけ読み飛ばしが起きるということです。

 「サブクエリをネストしたら遅くなる」というのは間違いではないですが、正しくもありません。

 「無駄に読み飛ばせば遅くなる」が正解です。

 初心者がよく間違うことは、WHERE句のサブクエリが複数レコード返したときに不安になったりすることです。WHERE句に条件を追加すれば、出力結果が減ることがあっても増えることはありません。

◇    ◇    ◇    ◇

 詳しい説明は、ハンズオンセミナーで行っています。

 もっと基本的な部分から、テーブルファンクション・OLAP関数ぐらいまで説明します。

 ご興味のある方はinfo@g1sys.co.jpまで。

Comment(3)

コメント

saki1208


saki1208です。

ずいぶんご無沙汰していましたが、年度末も過ぎ平常通りに戻ってきました。

Accessでも上記の各句でサブクエリの使用は可能ですよ。
もう十年ほどAccessはまともに触ってませんが、2003、2007では部分的に
確認してみました。

就職後に初めてまともに作ったプログラムはAccess1.1でした。誰も何も教
えてくれる人がいなくて、オンラインヘルプを参照しながら試行錯誤した
覚えがあります。Accessのマニュアルを借りて返って家で読んだり、自分仕
事以外のことを試してみたり。マクロではなく、すべてAccess Basicで作る
という要求でしたからすごく時間がかかりましたし、当時はすべてクエリも
しくはDAOを使用して作成しておりSQLを理解することはできませんでした
けど、今にして思えば原点だったかなと…

PC/AT互換機を初めて購入したのもその頃ですねぇ。

本題に関係ない話になっちゃいました。

saki1208


少し飲み過ぎのようです。

日本語がおかしいですが、適宜補完願います。(w)

saki1208 さん、おはようございます。

ホントですね。
Accessでもできました。

まともなプログラムを書いたときはAccess2.0で素人だったので、
できないものだと思っていました。

Accessで組んでいて、自分が言語仕様を決めるなら括弧書きで
サブクエリーが使えるように作るのに……と考えて、イロイロ
試したのでしたがダメであきらめました。

Oracleを初めて触ったときに試しにやってみたら、こたえが
返ってきてびっくり。

当時はFROM句でサブクエリーを使うためにユニークな名前の
クエリーを作ってから動的SQLで処理していたな……。

1995年ぐらいのAccessの教科書にはそんなこと書いてなかったし、
CreateQueryDef ……ってやって、ユニークにしないとマルチユーザ
で使えないので、名称管理含め、めちゃくちゃ苦労した恨みがあって、
「Accessはダメ!」って……。逆恨みだったのねorz

長~く使ってなかったから勘違いしていました。
勉強になりました。ありがとうございました。

コメントを投稿する