SQLer 生島勘富 のブログ

RDB・SQLの話題を中心に情報発信をしています。

FROM句とWHERE句

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

 SQLのSELECTは次の順で処理されます。
     FROM・WHERE句の中のサブクエリ
     FROM・WHERE句(WHERE句の中の相関サブクエリ)
     GROUP BY句
     HAVING句の中のサブクエリ
     HAVING句(HAVING句の中の相関サブクエリ)
     SELECT句
     ORDER BY句

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

まずはイメージから

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

図1 INNER JOINのイメージ

 一致するもののみを抽出するイメージです。
 あるいは、内側だけ(INNER)とイメージしてください。

図2 LEFT OUTER JOINのイメージ

 左側に記述したテーブルのデータをすべて抽出するイメージです。
 あるいは、左側は外側も(LEFT OUTER)とイメージしてください。

図3 RIGHT OUTER JOINのイメージ

 右側に記述したテーブルのデータをすべて抽出するイメージです。
 あるいは、右側は外側も(RIGHT OUTER)とイメージしてください。

図4 FULL OUTER JOINのイメージ

 結合によっての抽出は行わないイメージです。
 あるいは、すべて外側も(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 間違った例

     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ではちゃんと出た。リビジョン違いと言うことはバグ扱いかな?