Hatena::ブログ(Diary)

SQLer 生島勘富 の日記 このページをアンテナに追加 RSSフィード Twitter

2010-06-12

FROM句とWHERE句

 SQLが分からないという人は、文法を理解しようとしてしまっていることが多い。ですが、私は文法解説は極力やりません。SQLは全体を把握してイメージでとらえないとまっとうに書けないからです。

 SQLのSELECTは次の順で処理されます。

     FROM・WHERE句の中のサブクエリ

     FROM・WHERE句(WHERE句の中の相関サブクエリ)

     GROUP BY句

     HAVING句の中のサブクエリ

     HAVING句(WHERE句の中の相関サブクエリ)

     SELECT句

     ORDER BY句

 SQLが苦手だという人のほとんどは、最初に処理されるFROM句・WHERE句が理解できていません。SQLの基礎はFROM句とWHERE句で、これが理解できるだけで7〜8割できたのも同じですので、しっかりと身につけてください。

まずはイメージから

 TABLE_A と TABLE_B をそれぞれ B_ID と ID で結合するとすると、結合する種類によって、青色の部分が抽出されます。

図1 INNER JOINのイメージ

f:id:Sikushima:20100612114731g:image

 一致するもののみを抽出するイメージです。

 あるいは、内側だけ(INNER)とイメージしてください。

図2 LEFT OUTER JOINのイメージ

f:id:Sikushima:20100612114732g:image

 左側に記述したテーブルのデータをすべて抽出するイメージです。

 あるいは、左側は外側も(LEFT OUTER)とイメージしてください。

図3 RIGHT OUTER JOINのイメージ

f:id:Sikushima:20100612114733g:image

 右側に記述したテーブルのデータをすべて抽出するイメージです。

 あるいは、右側は外側も(RIGHT OUTER)とイメージしてください。

図4 FULL OUTER JOINのイメージ

f:id:Sikushima:20100612114735g:image

 結合によっての抽出は行わないイメージです。

 あるいは、すべて外側も(FULL OUTER)とイメージしてください。

左右を間違えない。

 JOINを書くとき、左右を逆に書く人がいます。

     FROM

       TABLE_A AS a

       LEFT JOIN TABLE_B AS b

         ON b.ID = a.B_ID

 しかし、SQL文は本来は1文になりますので1行で書くと、


 FROM TABLE_A AS a LEFT JOIN TABLE_B AS b ON b.ID = a.B_ID

 結合条件で逆になるのは、意味が分かってない証拠です。

抽出条件と結合条件

 よく間違えられるのは、抽出条件と結合条件をごっちゃにしているものです。

 例えば、TABLE_B は論理削除することになっていて、「削除FLG」という項目があって、図2の通りデータを抽出したいとします。

図5 間違った例

f:id:Sikushima:20100612115241g:image

     FROM

       TABLE_A AS a

       LEFT JOIN TABLE_B AS b

         ON a.B_ID = b.ID

     WHERE

       b.削除FLG = 0

 図の通り、紫の部分は

     「b.削除FLG が NULL」

に設定されているため、

     「NULL = 0」つまり、紫の部分はすべてFALSEになるため、抽出される結果は 図1(INNER JOIN)と同じになってしまいます。

 これは非常によく見られる間違いです。

 これを防ぐために

     FROM

       TABLE_A AS a

       LEFT JOIN

       (SELECT * FROM TABLE_B WHERE 削除FLG = 0) AS b

         ON a.B_ID = b.ID

とサブクエリにする人もいますけれど、サブクエリとのJOINではインデックスが使えませんので、TABLE_B.ID にインデックスがあっても利用できなくなり、非常に遅いクエリになります。

 正しくは、

     FROM

       TABLE_A AS a

       LEFT JOIN TABLE_B AS b

         ON a.B_ID = b.ID

         AND 0 = b.削除FLG

となります。

 このとき、

     FROM

       TABLE_A AS a

       LEFT JOIN TABLE_B AS b

         ON a.B_ID = b.ID

         AND b.削除FLG = 0

でも、同じ結果になりますがRDBMSのバージョンによってはならないこともある)*1先ほども書いたとおり、テーブルの左右は合わせるべきです。イメージとしては、

     「TABLE_Aにある 0 というリテラルと結合する

という、あくまでも「結合条件だ」というイメージで書きましょう。逆に書く人が多いのですけれど、逆に書いている人は

     「b.削除FLG = 0」は抽出条件だけどちゃんと動いてくれないからFROM句に書く

というイメージを持っていると思います。この感覚の違いがSQL文が複雑になると書けなくなる原因の一つになります。

 SQLを書くときは、必ず、抽出条件か、結合条件か、イメージしながら書きましょう。

*1:私の記憶では、Oracle9.1.4はNGで、Oracle9.1.6ではちゃんと出た。リビジョン違いと言うことはバグ扱いかな?

yesterdayyesterday 2010/06/12 19:34 こんにちは。前の続きです。
「ビジネスロジックはストアドで何でも(ほとんど)できる」というのはわかっている人にはわかっていると思いますし、実践している人もたくさんいると思います。
でも生島さんが啓蒙したいのはそういう人たちではなく、「できるわけねえよ、そんなの」と言う人たちなんですよね。
時間と暇をもてあましているサンデープログラマを除けば、プログラミングするのは企業に勤めている人のはずです。そういう人たちに「便利だからストアド勉強しようよ」と言っても、「時間と手間をかける価値が本当にあるのか?もし使い物にならなかったら、無駄にした時間を工数はどうなるんだ?」となるのではないでしょうか。
その認識を覆すには、誰にも疑う余地のない明確さで、ストアドの優位性を示す必要がありますね。
@ITのコラムに足りなかったのは、それではないでしょうか。

SikushimaSikushima 2010/06/13 05:51 yesterdayさん、おはようございます。

優位性は示しています。
彼らはできない目でしか見れないから、理解できないだけです。

それはオブジェクト指向がしっくり来ないから、全部staticという人と同じです。
「できない」前提の目でしか見れなかったら何を言っても、何を見せても理解はできません。

「できない」レベルは無限大にできない可能性があって、できる側から見たらレベルが低すぎて前提が全く分かりません。

理論上できるのに「前提を示せ!」って、到底、技術者の言うことじゃないのです。

できない前提でしか見れないのは、とても技術者とは呼べないっていってるわけです。

トラックバック - http://d.hatena.ne.jp/Sikushima/20100612/1276311628