「火星出身」で、なおかつ「年齢が30以上」の乗員を探したいとき、WHERE句を1つ書くだけで足りるでしょうか?
前回はWHERE句に「1つの条件」を書きました。では「2つ以上の条件を同時に満たす行」を探したいときは、どう書けばいいでしょう。少し考えてから読み進めてください。
複数条件を組み合わせるAND・OR・NOT
複数の条件を1つのWHERE句にまとめるには、AND・OR・NOTという3つの論理演算子を使います。
AND― 両方の条件を満たす行だけを残すOR― どちらか一方でも条件を満たす行を残すNOT― 条件を満たさない行を残す(条件を反転させる)
crewテーブルで確認しましょう。
crew テーブル:
| id | name | role | age | home | salary |
|---|---|---|---|---|---|
| 1 | ユミ | エンジニア | 24 | 地球 | 320000 |
| 2 | ケンジ | パイロット | 35 | 火星 | 400000 |
| 3 | サクラ | 医師 | 41 | 地球 | 520000 |
| 4 | ハルト | 医師 | 33 | 月 | 450000 |
| 5 | レイ | 研究員 | 29 | 火星 | 380000 |
| 6 | ミドリ | パイロット | 27 | 地球 | 360000 |
| 7 | ソラ | エンジニア | 45 | 月 | 470000 |
| 8 | トウマ | 研究員 | 24 | NULL | 270000 |
| 9 | アカリ | エンジニア | 31 | 火星 | 350000 |
| 10 | リョウ | パイロット | 38 | NULL | 440000 |
「火星出身」かつ「年齢30以上」を探すならANDです。
SELECT name, home, age
FROM crew
WHERE home = '火星' AND age >= 30;
結果:
| name | home | age |
|---|---|---|
| ケンジ | 火星 | 35 |
| アカリ | 火星 | 31 |
「医師」または「研究員」を探すならORです。
SELECT name, role
FROM crew
WHERE role = '医師' OR role = '研究員';
結果:
| name | role |
|---|---|
| サクラ | 医師 |
| ハルト | 医師 |
| レイ | 研究員 |
| トウマ | 研究員 |
「地球出身ではない」をNOTで書くと、こうなります。
SELECT name, home
FROM crew
WHERE NOT home = '地球';
結果:
| name | home |
|---|---|
| ケンジ | 火星 |
| ハルト | 月 |
| レイ | 火星 |
| ソラ | 月 |
| アカリ | 火星 |
地球出身以外の5名が返ってきました。これはWHERE home != '地球'と書いたときとまったく同じ結果になります。
ここで気をつけたいのが、配属先(home)が未定でNULLになっているトウマとリョウです。この2人はどちらの書き方でも結果に含まれません。なぜなら、NULLとの比較(home = '地球')は「真」でも「偽」でもなく「不明(わからない)」という特別な状態になり、NOTで反転させても「不明」は「不明」のままだからです。「わからない」の反対もやっぱり「わからない」、という感覚です。トウマとリョウのようにNULLの行まで拾いたいときは、home IS NULLを使います(IS NULLの使い方は次回くわしく学びます)。
優先順位とカッコ
AND・ORを一緒に使うときは、優先順位に注意が必要です。SQLではANDがORより先に評価されます。
たとえば「地球出身または火星出身の、エンジニア」を探したいとして、次のように書いてしまうとどうなるでしょうか。
SELECT name, home, role
FROM crew
WHERE home = '地球' OR home = '火星' AND role = 'エンジニア';
一見良さそうですが、ANDが先に評価されるため、実際には「home = '地球'」または「home = '火星' かつ role = 'エンジニア'」という意味になってしまいます。これでは地球出身の全員(ユミ・サクラ・ミドリ)が、役割に関係なく含まれてしまい、意図とズレます。
意図どおりに書くには、カッコ()でまとめます。
SELECT name, home, role
FROM crew
WHERE (home = '地球' OR home = '火星') AND role = 'エンジニア';
結果:
| name | home | role |
|---|---|---|
| ユミ | 地球 | エンジニア |
| アカリ | 火星 | エンジニア |
カッコで囲んだ部分が先に計算されるので、「地球か火星の出身者」という条件をひとまとめにしてから、「エンジニアである」という条件をANDでかけ合わせられます。複数条件を組み合わせるときは、AND/ORが混ざったら迷わずカッコをつける——これを習慣にしておくと、意図しない結果を防げます。
「役割がパイロットで、かつ年齢が35以上、または医師である」乗員を探したいとき、正しいWHERE句はどちらでしょう? WHERE role = 'パイロット' AND age >= 35 OR role = '医師' か WHERE (role = 'パイロット' AND age >= 35) OR role = '医師'
答えを見る
どちらも実は同じ結果になります。SQLではANDがORより先に評価されるため、カッコがなくてもrole = 'パイロット' AND age >= 35が先にまとまり、その結果にOR role = '医師'が続きます。ただし、読む人に意図を明確に伝えるためにも、カッコを書く習慣をつけておくのがおすすめです。
条件を自在に組み合わせられるようになると、データベースへの質問はぐっと表現力を増します。次回は「あいまいな条件」や「範囲」「リスト」での絞り込みを学びます。
/sql/game/ の SQL DIVER で、AND・OR・カッコの感覚を指先に覚えさせておきましょう。
ANDとORが混ざったら、とにかくカッコ! これさえ守れば、意図しない結果に振り回されることはないよ。