Menu

SQLite WHERE句の使い方 | LIKE・IN・BETWEEN完全ガイド

SQLiteのWHERE句で行を絞り込む方法を解説。比較演算子、AND/OR、LIKE、IN、BETWEEN、そして誰もがハマるNULLの落とし穴まで実例付きで紹介します。

このページのコードはエディタで実行できます — 編集してすぐに結果を確認できます。

WHERE句で行を1件ずつフィルタリングする

WHERE を付けずに SELECT を実行すると、テーブルの全行が返ってきます。実際にそれが欲しい場面はほとんどないはずです。WHERE 句を使えば、条件に合致する行だけを絞り込めます。SQLite はテーブルを順番にたどりながら各行に条件を当てはめ、真になった行だけを残してくれる、というイメージです。

返ってくるのは3行、NeuromancerHyperion、そして The Martian です。year > 1980 という条件が各行に対して評価され、マッチしたものだけが残ったわけですね。

イメージとしては、WHEREFROM と SELECT する列の間に挟まっているフィルターです。条件が true になった行だけが通り抜けてきます。

比較演算子

基本は想像どおりに動きます。

= は等価、!= または <> は「等しくない」、そして <<=>>= は大小比較に使います。文字列の比較も同じ演算子で、author = 'Asimov' は一文字単位で完全一致するレコードを返します。

ひとつ注意点があります。SQL では文字列リテラルにはシングルクォート、識別子(カラム名やテーブル名)にはダブルクォートを使うのが原則です。SQLite では歴史的な理由から WHERE author = "Asimov" が動いてしまうこともありますが、移植性がなく、たまたま「文字列」がカラム名と一致すると黙って誤動作することすらあります。文字列は必ずシングルクォートで囲みましょう。

AND・OR・括弧で複数条件を組み合わせる

実務のクエリでは、複数の条件を組み合わせることがほとんどです。AND は両方の条件が真でなければならず、OR はどちらか一方でも真ならマッチします。

最初のクエリは「最近の本」かつ「ページ数が少ない本」を絞り込みます。2つ目は、どちらかの著者で書かれた本を取り出すクエリです。

ANDOR を混在させると、優先順位で痛い目を見ることがよくあります。ANDOR よりも結合が強いので、次のようになります。

これは Herbert OR (Gibson AND year > 1980) と解釈されます。つまり、年に関係なくHerbertの本すべてと、1980年以降のGibsonの本、ということですね。たぶん意図したものとは違うはず。意図を明確にしたいなら、こんなふうにカッコでくくりましょう:

迷ったらカッコを付けておく。クエリオプティマイザは気にしないし、後でこのSQLを読む人にも感謝される。

NULLは値のように振る舞わない

これはWHERE句で誰もが一度はハマる落とし穴だ。SQLのNULLは「不明」を意味していて、不明なものは比較できない。だからcolumn = NULLは_偽_にはならず、結果はNULLになる。WHEREはそれを「この行はスキップ」として扱う。

IS NULLIS NOT NULL だけが NULL を直接判定できる演算子です。これは指に覚え込ませてください。それ以外の比較は NULL との比較がすべて NULL を返し、該当する行が静かに結果から消えてしまいます。

否定でも同じ罠があります。WHERE author != 'Asimov'author IS NULL の行を返してくれません。なぜなら NULL != 'Asimov' の結果も NULL になるからです。NULL の行も含めたいときは、WHERE author != 'Asimov' OR author IS NULL のように明示的に書く必要があります。

IN と BETWEEN:毎日のように使うショートカット

IN 演算子はリストに値が含まれているかを判定します。OR をいくつもつなげる代わりにスッキリ書ける書き方です。

BETWEEN は範囲を指定して絞り込む条件で、両端を含むのがポイントです。

year BETWEEN 1980 AND 2000year >= 1980 AND year <= 2000 とまったく同じ意味で、単に書き方が短いだけです。注意点としては、両端の値も含まれることを覚えておきましょう。両端を除外したい場合は、比較演算子で書き下す必要があります。

INNULL の組み合わせについても一言。WHERE column NOT IN (1, 2, NULL) と書くと、いかなる行も返ってきません。なぜなら NULL との比較結果は常に NULL になるからです。リストから NULL を除外するか、IS NULL を使って別途扱うようにしましょう。

LIKE によるパターンマッチング

LIKE は文字列のパターンマッチングを行う演算子で、2種類のワイルドカードが使えます。

  • % は任意の長さの文字列にマッチします(0文字でもOK)。
  • _ はちょうど1文字にマッチします。

SQLiteのLIKEは、ASCII文字に関してはデフォルトで大文字小文字を区別しません。つまり 'Dune' LIKE 'dune' は真になります。Postgresから来た人にとってはちょっと意外かもしれませんね。PostgresではLIKEは大文字小文字を区別し、区別しないバージョンはILIKEとして用意されています(ちなみにSQLiteにILIKEはありません)。

どうしても大文字小文字を区別して一致させたい場合は、選択肢が2つあります。1つ目はグローバルなpragmaを切り替える方法です:

PRAGMA case_sensitive_like = ON;

あるいは GLOB を使う方法もあります。こちらは常に大文字・小文字を区別し、Unix風のワイルドカード(任意の文字列を表す *、1文字を表す ?)が使えます。

GLOB 'd*' だと、大文字小文字が区別されるので何もマッチしません。

日付で絞り込む

SQLite は日付をテキスト(通常は YYYY-MM-DD か ISO 8601 形式)として保存します。そのため、ISO 形式さえ守っていれば、文字列の比較がそのまま日付の比較として機能してくれます。

'2024-06-01' < '2024-11-08' は文字列として比較しても日付として比較しても true になるので、こうしたクエリは期待どおりに動きます。ところが '15/01/2024''Jan 15 2024' のような別フォーマットで日付を保存していると、比較結果がエラーも出さずに間違った値になってしまいます。日付は必ず ISO 8601 形式で保存しましょう。あとあと自分が助かります。

もう少し凝った日付計算(年だけ取り出す、「今日」と比較する、など)には、SQLite の date()strftime()julianday() といった関数が使えます。これらは日付・時刻の章でまとめて取り上げます。

複数条件を組み合わせて使う

ここまで紹介した WHERE 句の条件をいくつか組み合わせた例を見てみましょう。

上から順に読んでみてください。年が判明していて、範囲内に収まり、指定した2人の著者のどちらか または 十分な長さがあり、かつ下書きではない行だけが残ります。これこそ WHERE 句の本領発揮で、小さくて読みやすい条件を組み合わせて、狙ったレコードをきっちり絞り込めるわけです。

身につけておきたい習慣が2つあります。

  • 条件は1行ずつインデントして書く。長い WHERE 句を1行にまとめると、あっという間に読めなくなります。
  • 意図が一目で分からない条件には コメント を添える。-- 下書きを除外 の一言があるだけで、後から見返したときの安心感がまるで違います。

次回: 演算子と NULL を深掘り

WHERE 句の正体は、結局のところ列に対して演算子を適用しているだけ。そして NULL は、あらゆる演算子の挙動をひっそり変えてしまう曲者です。次のページでは SQLite の演算子をさらに掘り下げます。算術演算、|| による文字列連結、IS 系の比較、そして三値論理まで踏み込むので、「えっ、そうなるの?」という驚きが減っていくはずです。

よくある質問

SQLiteのWHERE句はどう動くの?

WHEREは各行に条件を当てて、結果が真になった行だけを残す仕組みです。条件が偽またはNULLになった行は除外されます。書く位置はFROMの直後で、SELECT ... FROM table WHERE 条件という形になります。

WHERE句で複数の条件を組み合わせるには?

ANDORを使います。ANDは両方が真のときだけ、ORはどちらか一方が真ならOKです。注意したいのはANDのほうがORより優先度が高いこと。混在させるときはWHERE (a OR b) AND cのようにカッコで明示するのが安全です。

WHERE column = NULL が効かないのはなぜ?

NULLは「値が不明」という意味なので、=!=で比較しても結果は真でも偽でもなくNULLになってしまいます。WHEREは真の行しか残さないので、当然ヒットしません。NULLを判定したいときは専用のIS NULLIS NOT NULLを使ってください。

SQLiteのLIKEは大文字・小文字を区別する?

デフォルトでは、ASCII文字に関してはLIKEは大文字・小文字を区別しません。つまり'Hello' LIKE 'hello'は真になります。区別したいときはPRAGMA case_sensitive_like = ON;を設定するか、常にケースを区別するGLOB(ワイルドカードはUnix風の*?)を使うのが定番です。

Coddy programming languages illustration

Coddyでコードを学ぼう

始める