【SQL初心者向け】JOINするときに他のことに気を取られないように

こんにちは。花粉が落ち着いてきてきました。最近だと雨の日も多くて梅雨も近そうですね。
私はMySQL相手に格闘する日々を過ごしていますが、最近は分析に挑戦したいマーケターやPMたちがSQLに手を出すようになってきました。調べてみると「SQL使えるようになると世界が変わる!」なんて記事も多く存在しています。今やGoogle BigQuery、Redash、Metabase、DBeaverなどなど、DBと連携・接続してSQLを叩いて分析に使えるツールが山ほどあるので是非ともエンジニアと話しながら挑戦していってもらいたいですね。

で、実際に分析でSQLを叩くとすればSELECTがほとんどだと思いますがテーブルを結合したいですよね。そんなときにJOIN句が利用できるのですが、つい最近JOINで大失敗してしまったので、JOINするときは気を付けましょうってことで、うっかりやってしまいがちなミスをいくつか書いていきます。

ON条件の書き忘れ or 条件が常にtrueになる地獄

最後のJOINを書いているときに「黒田さーん」なんて声を掛けられたものだから、このまま実行してしまって大変なことになりました。クロス結合です。一つ一つのデータの結合に対して条件がないのでusersとordersのデータの組み合わせ全てのデータが降ってきます。

下記は注文データ(orders)に対して会員データ(users)を紐づけて表示したいときの例です。

誤)SELECT * FROM orders JOIN users;
)SELECT * FROM orders JOIN users On orders.user_id = users.id;

 × 

上記のordersテーブルとusersテーブルの場合、↓のようにしたいのに

誤った場合だと↓のようになってしまう

たった5件ずつのデータでも5×5の25件データがあるのでデータ量が多いとPCが爆発しそうです。
ON条件はおまじないとして必ず入っているかチェックしましょう。

INNER JOINとLEFT JOINの選択を間違える

INNER JOINは「両方にデータがあるときだけ出す」ので片方にしかないデータは出力されません
「うちの会員数減ってるんですけど」と焦る前にJOIN句を見なおしましょう。

下記は会員データ(users)に対して注文データ(orders)を紐づけて表示したいときの例です。
条件として「一度も注文していない会員データも表示する」こととします。

誤)SELECT * FROM users INNER JOIN orders On users.id = orders.user_id;
)SELECT * FROM users LEFT JOIN orders On users.id = orders.user_id;

一度も注文していない会員データを表示する正しいSQLの場合は↓となります。

一方でJOINの種類を間違えてしまった場合が↓になります。

INNER JOINは両方にデータがないと表示されないため、データ数が少ない状態になってしまいます。

INDEXを意識せずJOINする

これはJOINに限ったことではないのですが、インデックスがない場合は全件スキャンが走るためデータ量が多いと激重になってしまいます。

SELECT * FROM users LEFT JOIN orders On users.id = orders.user_id;

上記のSQLの場合はorders.user_idにインデックスが必要になります。(users.idはプライマリーキーと考える)

インデックスを作る作業はエンジニアになるケースが多いので、分析に必要なSQLをエンジニアと共有したうえで最適な状態でSQLを実行しましょう。

まとめ

JOINというのは、書くだけなら簡単なんです。

SQLは書けるときは簡単に見えるけど、ちょっとした油断で全然違う結果になったりします。
僕も何度も爆発させてきたので、これからSQLに挑戦するみなさんも、ゆっくり丁寧にやっていきましょう。
JOINの先に欲しいデータが取得できますように。