SQLを使ってデータを抽出する時、抽出対象のレコードを抽出するために指定するのが「WHERE」句です。
ビジネスの場面では、WHERE句を使わないクエリを使うことはほぼ無いでしょう。
何かしらの絞り込みを指定することがほとんどです。
しっかり使い方をマスターしておきましょう。
初心者はWHERE句で2つのポイントをおさえればOK!
- WHERE句で指定した条件式でTRUEになるレコードだけを抽出できる。
- ビジネスパーソンが使う時は、沢山の条件をANDでつなぐことが多い。
最初に演習用サンプルデータを説明します
当記事の解説で利用するサンプルデータです。
SELECT句で試したように、魔法の呪文としてコピペしてご利用ください。
-- サンプルデータ -- ここから
WITH sample AS (
SELECT * FROM UNNEST(ARRAY<STRUCT<account_id INT64, account_name STRING, birthday DATE, is_certified BOOL, is_deleted BOOL>>[
(1, "taro", DATE("2000-01-01"), TRUE, FALSE),
(2, "hanako", DATE("1999-12-31"), TRUE, FALSE),
(3, "pochi", CAST(NULL AS DATE), FALSE, FALSE),
(4, "mike", DATE("2010-10-10"), TRUE, FALSE),
(5, "yukichi", DATE("1835-01-10"), TRUE, TRUE)
])
)
-- サンプルデータ -- ここまで
account_id | account_name | birthday | is_certified | is_deleted |
---|---|---|---|---|
1 | taro | 2000/01/01 | TRUE | FALSE |
2 | hanako | 1999/12/31 | TRUE | FALSE |
3 | pochi | NULL | FALSE | FALSE |
4 | mike | 2010/10/10 | TRUE | FALSE |
5 | yukichi | 1835/01/10 | TRUE | TRUE |
アカウント情報を格納したテーブルで、birthday(誕生日)、is_certified(認証済フラグ)、is_deleted(削除済フラグ)のカラムを用意しています。
WHERE句を使うと抽出レコードを絞ることができる
SELECT句では抽出したいカラムを選択できました。
FROM句では参照するデータソースを選択できました。
WHERE句では、抽出したいレコードを指定することができます。
WHERE句を使えるようになれば、FROM句で指定したデータソースから、欲しいレコードの欲しいカラムだけを抽出できるようになります。
WHERE句の後ろには条件式を書く
SELECT句では、「SELECT」と書いた後に抽出したいカラムを入力しました。
FROM句では、「FROM」と書いた後に参照したいデータソースを入力しました。
WHERE句では、「WHERE」と書いた後に条件式を入力します。
WHERE句の後ろに書いた条件式は、参照データソースのレコード1行毎に判定が行われます。
たとえば参照データソースに3行のレコードがあれば、1行目の条件式判定結果、2行目の条件式判定結果、3行目の条件式判定結果があるわけです。
その中で、条件式判定結果がTRUEだったレコードだけが抽出されるようになっています。
FALSEになったレコードは抽出対象外となります。
実務でIDを指定してデータを抽出する場面は多い
実務の場面では、何か特徴的なレコードを抽出する際、ID(プライマリキー)が分かっていて、それを使って抽出する場面によく遭遇します。
たとえば、「account_idが2のユーザさんから、ログインできない旨の問い合わせがあったから調べて」、といった具合です。
その時に使うWHERE句を例に試してみましょう。
-- 演習01
SELECT * FROM sample
WHERE account_id = 2
実際にクエリを実行した結果がこちら。
account_idが「2」のレコードだけが抽出されています。
WHERE句の後ろの条件式「account_id = 2」が判定されています。
1レコードずつ、各レコードのaccount_idカラムを見て、「2」と一致するか一致しないかを評価して、TRUEになったレコードだけを抽出し、TRUEにならなかったレコードは抽出しないようになっています。
今回のサンプルデータは5レコードのみですが、実際の業務では、何万何億のレコードの中から抽出することになります。
抽出対象が複数ある時はIN句を使います。
-- 演習02
SELECT * FROM sample
WHERE account_id IN (1, 2)
実際にクエリを実行した結果がこちら。
account_idが「1」と「2」のレコードだけが抽出されています。
WHERE句の後ろの条件式「account_id IN (1, 2)」が判定されています。
1レコードずつ、各レコードのaccount_idカラムを見て、「1」か「2」と一致するか一致しないかを評価して、TRUEになったレコードだけを抽出し、TRUEにならなかったレコードは抽出しないようになっています。
さらに実践的な場面を想定すると、「JOIN句」や「副問い合わせ」についての理解が必要になります。
それが使えると、抽出対象が沢山存在するケースにも対応できます。
初心者は勉強を後回しにしましょう。
JOIN句を解説する記事へのリンクを設置予定
副問い合わせを解説する記事へのリンクを設置予定
また、「プライマリキー」という単語が登場していますが、初心者はこれも勉強を後回しにしましょう。
プライマリキーを解説する記事へのリンクを設置予定
何かの特徴を持つレコードを抽出する場面でも使う
実務でデータ分析する時、「こういう特徴を持つユーザはどれくらい存在するだろうか」と、特徴を基準に抽出する場面がよくあります。
たとえば、「10歳以上、30歳以下のユーザがどれくらいいるか調べて」、といった具合です。
次の演習では、条件を少し簡単にし、誕生日が1993/01/01から2013/01/01の間のアカウントを抽出するようにしています。
-- 演習03
SELECT * FROM sample
WHERE birthday BETWEEN DATE("1993-01-01") AND DATE("2013-01-01")
実際にクエリを実行した結果がこちら。
WHERE句の後ろの条件式「birthday BETWEEN DATE(“1993-01-01”) AND DATE(“2013-01-01”)」が判定されています。
1レコードずつ、birthdayカラムを見て評価し、TRUEになったレコードだけを抽出し、TRUEにならなかったレコードは抽出しないようになっています。
ちなみに、条件式の中で計算もできるため、正確に誕生日を把握し利用する場面では下記のようになります。
初心者には難しいでしょうから、こんなこともできるようになる、くらいの感覚で見てみましょう。
-- 演習04
SELECT *,
CAST(FLOOR((CAST(FORMAT_DATE("%Y%m%d", CURRENT_DATE("Asia/Tokyo")) AS INT64) - CAST(FORMAT_DATE("%Y%m%d", birthday) AS INT64)) / 10000) AS INT64) AS age
FROM sample
WHERE CAST(FLOOR((CAST(FORMAT_DATE("%Y%m%d", CURRENT_DATE("Asia/Tokyo")) AS INT64) - CAST(FORMAT_DATE("%Y%m%d", birthday) AS INT64)) / 10000) AS INT64) BETWEEN 10 AND 30
実際にクエリを実行した結果がこちら。
「副問い合わせ」などを使うことで、もっとキレイなクエリになるのですが、今回は利用しない書き方にしています。
BOOL型でレコードを絞る場面もよくある
たとえば、「キャンペーン対象のアカウントの一覧が欲しいから、認証済のアカウントだけ抽出して」といった指示があったとしましょう。
-- 演習05
SELECT * FROM sample
WHERE is_certified
実際にクエリを実行した結果がこちら。
条件式を処理した結果はBOOL型になるので、BOOL型のカラムを使えば、カラム名だけ書く形でOKです。
「is_certified = TRUE」のように明示的に書いても良いのですが、慣れると面倒に感じるようになるでしょう。
もう一つ例を挙げ、「未削除のアカウントの一覧を抽出して」といった指示を想定してみましょう。
-- 演習06
SELECT * FROM sample
WHERE NOT is_deleted
実際にクエリを実行した結果がこちら。
条件式「NOT is_deleted」が評価され、is_deletedがFALSEのレコードが評価結果TRUEになり、抽出されています。
実務では沢山の条件をANDでつなぐ場面が多い
実務では、もっと複雑な条件で抽出を要求されることが多いです。
「キャンペーン対象の条件は、20歳以上で未削除・認証済のアカウントにする」といった場合を例にしてみます。
ただし、「20歳以上」の条件を簡略化し、「誕生日が2003/01/01より前」と解釈します。
SELECT * FROM sample
WHERE birthday < DATE("2003-01-01")
AND is_certified
AND NOT is_deleted
実際にクエリを実行した結果がこちら。
条件式「birthday < DATE(“2003-01-01”) AND is_certified AND NOT is_deleted」が評価され、TRUEになったレコードのみが抽出されています。
実務では「AND」(かつ)を使うことが多く、WHERE句では「AND」毎に改行する人が多いです。
この書き方には慣れておきましょう。
WHERE句が無いクエリは「WHERE TRUE」と書くのと同じ結果になる
余談ですが、「WHERE TRUE」と書いた場合、1レコードずつ評価し、どのレコードでもTRUEが返されるため、全てのレコードが抽出されることになります。
WHERE句を省略した時と同じ結果になります。
SELECT * FROM sample
WHERE TRUE
実際にクエリを実行した結果がこちら。
条件式の結果がNULLになっているレコードは抽出されない
WHERE句で指定した条件式をレコード毎に判定し、TRUEのレコードだけが抽出され、FALSEのレコードは抽出されません。
ではNULLはどうなるかというと、SQLでは抽出対象外の扱いとなります。
抽出されてほしいレコードが抽出されない、といった想定外の挙動(不具合)につながるので、条件式を書く時には必ず、「この条件式はNULLになることはあるんだろうか」と気配りする必要があります。
よくある不具合なので覚えておきましょう。
条件式でNULLが登場した時はIFNULL
「もしNULLだったら」の条件分岐にはIFNULL関数を使えます。
適切に使って、NULLだった時の代替値を設定しましょう。
ただし、条件式の結果がNULLになった時は、元々取り扱っているデータ自体が想定外だった可能性があるため、どのように修正するのかは熟考する必要があります。
「WHERE TRUE」から書き始める人もいる
TRUEならどのレコードも絞っていないのではないか、と疑問に思われる方もいらっしゃるでしょうから、そういう書き方もあることをご紹介しておきます。
クエリを書きながら試行錯誤していると、WHERE句で色々な条件の組み合わせを試す場面に遭遇します。
条件1かつ条件2かつ条件3を試した後に、やっぱり条件2かつ条件3で試してみよう、といった具合です。
WHERE 条件1
AND 条件2
AND 条件3
その時こんな書き方をしていると、1行目を消した後に2行目の「AND」を「WHERE」に書き換えることになります。
WHERE 条件2
AND 条件3
「WHERE TRUE」で書き始める書き方では、「AND」を「WHERE」に書き換える手間がなくなります。
WHERE TRUE
AND 条件1
AND 条件2
AND 条件3
2行目を消すだけで、「AND」を「WHERE」に書き換える必要が無いわけです。
WHERE TRUE
AND 条件2
AND 条件3
必ずこの書き方をしなければならないというわけではないので、Tipsとして覚えておきましょう。
また、稀に「WHERE TRUE」でなく「WHERE 1 = 1」と書き始める人もいますが、条件式の判定結果はTRUEなので変わりないです。
抽出レコードを絞るのにLIMIT句を使う方法もある
用途は異なりますが、抽出レコードを絞る、という意味ではLIMIT句も同じ機能です。
WHERE句は条件に合うレコードのみを抽出するので利用場面が多いですが、LIMIT句ではレコード数で絞るため、非エンジニアでの利用場面があまりありません。
詳しくはORDER BY句で解説するので、そちらをご一読ください。
ORDER BY句を解説する記事へのリンクを設置予定
振り返り
お疲れさまでした。
条件式をしっかり勉強した後であれば、そんなに苦労せず勉強できたのではないでしょうか。
実のところ、条件式をWHERE句専用の書き方だと勉強してしまうと、WHERE句で覚えることを多く感じてしまったり、条件式を応用したクエリを見た時に混乱してしまい、苦手意識を持ってしまうことがあります。
条件式の勉強を読み直される場合は、下記リンクからご覧ください。
条件式を解説する記事へのリンクを設置予定
WHERE句をマスターした次は、「ORDER BY」句です。
下記リンクから読み進めてください。
ORDER BY句を解説する記事へのリンクを設置予定