WHERE 句を使って、条件に合う行だけを取り出します。「営業部の社員」「30歳以上の社員」「東京都か京都府に住む社員」「名前が田で始まる社員」といった絞り込みを、比較演算子や AND・OR、BETWEEN・IN・LIKE で書けるようになります。WHERE 句は、次の章で学ぶ UPDATE・DELETE でも同じ書き方で使います。
この章で学ぶこと
-
WHERE句の位置と、比較演算子(=・<>・>・>=・<・<=) - 文字の値と日付の値の条件の書き方
- 条件を組み合わせる
AND・OR・NOTと、() - 範囲の
BETWEEN、候補のIN、あいまい検索のLIKE - NULL の条件
IS NULL・IS NOT NULL
6.1 WHERE 句の基本
WHERE 条件 を FROM テーブル名 の後ろに書くと、条件に合う行だけ が取り出されます。営業部(部署ID 2)の社員を取り出してみましょう。
SELECT NAME, DEPT_ID FROM EMPLOYEE WHERE DEPT_ID = 2 ORDER BY EMP_ID;
| NAME | DEPT_ID |
|---|---|
| 雷禅 海皇 | 2 |
| 佐藤 健太 | 2 |
| 伊藤 さくら | 2 |
| 渡辺 大輔 | 2 |
10人のうち、DEPT_ID が 2 の4人だけが表示されました。SELECT 文の句の順番は、次のとおり決まっています。
SELECT 列名, ...
FROM テーブル名
WHERE 条件
ORDER BY 列名;
WHERE は FROM の後、ORDER BY の前です。順番を入れ替えると「ORA-00933: SQLコマンドが正しく終了されていません。」というエラーになります。
条件は、行ごとに「成り立つ」か「成り立たない」かが判定され、成り立つ行だけが結果に残ります。DEPT_ID = 2 は、「DEPT_ID の値が 2 と等しい」という条件です。条件に合う行が1行も無いときは、結果は0行になります。これはエラーではありません。
SELECT NAME, AGE FROM EMPLOYEE WHERE AGE = 100;
「問合せ結果」には見出しだけが表示され、行はありません。
6.2 比較演算子
値を比べる記号を 比較演算子 といいます。
| 演算子 | 意味 | 例 |
|---|---|---|
= |
等しい | DEPT_ID = 2 |
<> |
等しくない(!= とも書ける) |
DEPT_ID <> 2 |
> |
より大きい | AGE > 30 |
>= |
以上 | AGE >= 30 |
< |
より小さい(未満) | AGE < 25 |
<= |
以下 | AGE <= 25 |
30歳以上の社員を取り出します。
SELECT NAME, AGE FROM EMPLOYEE WHERE AGE >= 30 ORDER BY EMP_ID;
| NAME | AGE |
|---|---|
| 佐藤 健太 | 31 |
| 高橋 翔 | 35 |
| 渡辺 大輔 | 42 |
25歳未満の社員を取り出します。
SELECT NAME, AGE FROM EMPLOYEE WHERE AGE < 25 ORDER BY EMP_ID;
| NAME | AGE |
|---|---|
| 林檎 星飛 | 24 |
| 田中 美咲 | 24 |
| 伊藤 さくら | 22 |
営業部以外の社員を取り出します。
SELECT NAME, DEPT_ID FROM EMPLOYEE WHERE DEPT_ID <> 2 ORDER BY EMP_ID;
| NAME | DEPT_ID |
|---|---|
| 院照 心愛 | 1 |
| 林檎 星飛 | 3 |
| 田中 美咲 | 3 |
| 鈴木 花子 | 1 |
| 高橋 翔 | 3 |
| 中村 結衣 | 3 |
【ご注意】記号の向きと順番
「以上」は >=、「以下」は <= です。=> や =< と逆に書くと「ORA-00920: 関係演算子が無効です。」というエラーになります。「等しい」は = 1つです。プログラミング言語の == と書くとエラーになります。
6.3 文字と日付の条件
文字の値
文字の列を条件にするときは、値を ' で囲みます(第4章の INSERT と同じです)。
SELECT EMP_ID, NAME, ADDRESS FROM EMPLOYEE WHERE NAME = '雷禅 海皇';
| EMP_ID | NAME | ADDRESS |
|---|---|---|
| 1 | 雷禅 海皇 | 大阪府 |
文字の値は、1文字でも違えば一致しません。姓と名の間の空白を抜いて '雷禅海皇' と書くと、結果は0行になります。英字の場合は、大文字と小文字も区別されます。
' を忘れて WHERE NAME = 雷禅 海皇 と書くと、Oracle は「雷禅」を列名だと解釈しようとして、「ORA-00933: SQLコマンドが正しく終了されていません。」などのエラーになります。
日付の値
日付の列を条件にするときは、DATE '年-月-日' で書きます。2000年以降に生まれた社員を、生年月日の順に取り出します。
SELECT NAME, BIRTH_DATE FROM EMPLOYEE WHERE BIRTH_DATE >= DATE '2000-01-01' ORDER BY BIRTH_DATE;
| NAME | BIRTH_DATE |
|---|---|
| 雷禅 海皇 | 2000-06-22 00:00:00 |
| 中村 結衣 | 2000-09-03 00:00:00 |
| 林檎 星飛 | 2001-12-24 00:00:00 |
| 田中 美咲 | 2002-03-05 00:00:00 |
| 伊藤 さくら | 2004-05-20 00:00:00 |
日付は、新しいほど大きい値として比べられます。「2000年1月1日以上」は「2000年1月1日かそれより後」という意味です。
6.4 条件を組み合わせる:AND・OR・NOT
AND:両方を満たす
2つの条件を AND でつなぐと、両方を満たす 行だけが残ります。開発部(部署ID 3)の女性(性別 2)を取り出します。
SELECT NAME, GENDER, DEPT_ID FROM EMPLOYEE WHERE DEPT_ID = 3 AND GENDER = 2 ORDER BY EMP_ID;
| NAME | GENDER | DEPT_ID |
|---|---|---|
| 田中 美咲 | 2 | 3 |
| 中村 結衣 | 2 | 3 |
OR:どちらかを満たす
OR でつなぐと、どちらか一方でも満たす 行が残ります。東京都か京都府に住む社員を取り出します。
SELECT NAME, ADDRESS FROM EMPLOYEE WHERE ADDRESS = '東京都' OR ADDRESS = '京都府' ORDER BY EMP_ID;
| NAME | ADDRESS |
|---|---|
| 院照 心愛 | 京都府 |
| 林檎 星飛 | 東京都 |
| 佐藤 健太 | 東京都 |
| 高橋 翔 | 東京都 |
| 中村 結衣 | 京都府 |
OR の両側には、それぞれ完全な条件を書きます。ADDRESS = '東京都' OR '京都府' とは書けません。
AND と OR を混ぜるときは ( ) を付ける
「営業部で、東京都か大阪府に住む社員」を取り出したいとします。次のように書くと、意図と違う結果になります。
SELECT NAME, DEPT_ID, ADDRESS FROM EMPLOYEE
WHERE DEPT_ID = 2 AND ADDRESS = '東京都' OR ADDRESS = '大阪府'
ORDER BY EMP_ID;
| NAME | DEPT_ID | ADDRESS |
|---|---|---|
| 雷禅 海皇 | 2 | 大阪府 |
| 佐藤 健太 | 2 | 東京都 |
| 鈴木 花子 | 1 | 大阪府 |
総務部(部署ID 1)の鈴木さんが入ってしまいました。AND は OR より先に判定されるので、この条件は「(営業部 かつ 東京都)または 大阪府」と解釈されたからです。意図どおり「営業部 かつ(東京都 または 大阪府)」にするには、( ) で囲みます。
SELECT NAME, DEPT_ID, ADDRESS FROM EMPLOYEE
WHERE DEPT_ID = 2 AND (ADDRESS = '東京都' OR ADDRESS = '大阪府')
ORDER BY EMP_ID;
| NAME | DEPT_ID | ADDRESS |
|---|---|---|
| 雷禅 海皇 | 2 | 大阪府 |
| 佐藤 健太 | 2 | 東京都 |
【再確認】AND と OR を混ぜるときは、必ず ( ) で囲む
AND と OR が両方ある条件は、意図どおりに解釈されているつもりでも間違えやすい箇所です。先に判定させたいまとまりを、必ず ( ) で囲んで 書いてください。囲まなくても結果が同じになる場合でも、読む人のために囲んでおきます。
NOT:条件を反転する
条件の前に NOT を付けると、その条件を満たさない 行が残ります。東京都以外に住む社員を取り出します。
SELECT NAME, ADDRESS FROM EMPLOYEE WHERE NOT ADDRESS = '東京都' ORDER BY EMP_ID;
| NAME | ADDRESS |
|---|---|
| 雷禅 海皇 | 大阪府 |
| 院照 心愛 | 京都府 |
| 田中 美咲 | 愛知県 |
| 鈴木 花子 | 大阪府 |
| 伊藤 さくら | 兵庫県 |
| 渡辺 大輔 | 神奈川県 |
| 中村 結衣 | 京都府 |
この条件は ADDRESS <> '東京都' と同じ結果です。NOT は、この後の NOT IN・NOT LIKE・IS NOT NULL のように、ほかの条件と組み合わせて使うことが多いです。
6.5 範囲と候補:BETWEEN・IN
BETWEEN:範囲
列名 BETWEEN 下限 AND 上限 は、「下限以上、上限以下」という範囲の条件です。25歳から30歳までの社員を取り出します。
SELECT NAME, AGE FROM EMPLOYEE WHERE AGE BETWEEN 25 AND 30 ORDER BY AGE;
| NAME | AGE |
|---|---|
| 雷禅 海皇 | 26 |
| 中村 結衣 | 26 |
| 院照 心愛 | 27 |
| 鈴木 花子 | 29 |
AGE >= 25 AND AGE <= 30 と書いても同じ結果です。BETWEEN は 両端を含みます(25歳と30歳の人がいれば含まれます)。日付にも使えます。
SELECT NAME, BIRTH_DATE FROM EMPLOYEE
WHERE BIRTH_DATE BETWEEN DATE '1995-01-01' AND DATE '1999-12-31'
ORDER BY BIRTH_DATE;
| NAME | BIRTH_DATE |
|---|---|
| 佐藤 健太 | 1995-04-12 00:00:00 |
| 鈴木 花子 | 1997-01-30 00:00:00 |
| 院照 心愛 | 1999-07-11 00:00:00 |
IN:候補のどれか
列名 IN (値1, 値2, ...) は、「値が候補のどれかと等しい」という条件です。6.4 で OR を使って書いた条件は、IN で短く書けます。東京都・京都府・大阪府に住む社員を取り出します。
SELECT NAME, ADDRESS FROM EMPLOYEE
WHERE ADDRESS IN ('東京都', '京都府', '大阪府')
ORDER BY ADDRESS, EMP_ID;
| NAME | ADDRESS |
|---|---|
| 院照 心愛 | 京都府 |
| 中村 結衣 | 京都府 |
| 雷禅 海皇 | 大阪府 |
| 鈴木 花子 | 大阪府 |
| 林檎 星飛 | 東京都 |
| 佐藤 健太 | 東京都 |
| 高橋 翔 | 東京都 |
NOT IN にすると、候補のどれでもない行が残ります。
SELECT NAME, ADDRESS FROM EMPLOYEE
WHERE ADDRESS NOT IN ('東京都', '京都府', '大阪府')
ORDER BY EMP_ID;
| NAME | ADDRESS |
|---|---|
| 田中 美咲 | 愛知県 |
| 伊藤 さくら | 兵庫県 |
| 渡辺 大輔 | 神奈川県 |
第3章の CHECK 制約 CHECK (GENDER IN (1, 2)) も、この IN です。「GENDER が 1 か 2 のどちらか」という条件を満たす値だけを入れられる、という意味でした。
6.6 あいまい検索:LIKE
列名 LIKE 'パターン' は、文字の値が パターンに当てはまる かを調べる条件です。パターンには、次の2つの特別な記号を使えます。
| 記号 | 意味 | 例 | 当てはまる値 |
|---|---|---|---|
% |
0文字以上の、どんな文字の並びにも当てはまる | '田%' |
「田」で始まる値(田中 美咲) |
_ |
ちょうど1文字の、どんな文字にも当てはまる | '_村%' |
2文字目が「村」の値(中村 結衣) |
名前が「田」で始まる社員を取り出します。
SELECT NAME FROM EMPLOYEE WHERE NAME LIKE '田%';
| NAME |
|---|
| 田中 美咲 |
名前が「子」で終わる社員を取り出します。
SELECT NAME FROM EMPLOYEE WHERE NAME LIKE '%子';
| NAME |
|---|
| 鈴木 花子 |
名前に「藤」を含む社員を取り出します。前後に % を付けると、どこにあっても当てはまります。
SELECT NAME FROM EMPLOYEE WHERE NAME LIKE '%藤%' ORDER BY EMP_ID;
| NAME |
|---|
| 佐藤 健太 |
| 伊藤 さくら |
住所が「府」で終わる社員(大阪府・京都府)を取り出します。
SELECT NAME, ADDRESS FROM EMPLOYEE WHERE ADDRESS LIKE '%府' ORDER BY EMP_ID;
| NAME | ADDRESS |
|---|---|
| 雷禅 海皇 | 大阪府 |
| 院照 心愛 | 京都府 |
| 鈴木 花子 | 大阪府 |
| 中村 結衣 | 京都府 |
NOT LIKE にすると、パターンに当てはまらない行が残ります。LIKE に % も _ も書かなければ、= と同じ「完全に一致」の条件になります。
【便利な使い方】現場での LIKE
社員管理アプリの「名前の一部で検索」のような機能は、LIKE '%入力した文字%' で実現します。ただし、先頭に % を付けた検索は、テーブルのすべての行を調べることになるため、行数が多いテーブルでは時間がかかります。業務のシステムで大量のデータを扱うときは、検索の仕方を設計の段階で考えます。
6.7 NULL の条件:IS NULL
第3章で学んだとおり、NULL は「値が入っていない」状態です。NULL の行を探すときは、= ではなく IS NULL を使います。
SELECT NAME, ADDRESS FROM EMPLOYEE WHERE ADDRESS IS NULL;
この教材の社員テーブルは、すべての列が NOT NULL なので、結果は 0行 です。NULL の行があれば、その行が表示されます。反対に、値が入っている行を探すときは IS NOT NULL を使います。
【ご注意】= NULL と書いても見つからない
WHERE ADDRESS = NULL と書いても、エラーにはなりませんが、1行も見つかりません。NULL は「値が無い」状態なので、「NULL と等しい」という比較は成り立たないと判定されるためです。<> NULL も同じです。NULL を調べるときは、必ず IS NULL・IS NOT NULL を使ってください。
この教材のテーブルには NULL が入りませんが、第10章でテーブルを結合すると、「社員のいない部署」の社員の列が NULL になります。そこで IS NULL が役に立ちます。
6.8 WHERE と ORDER BY を組み合わせる
ここまでの例でも使ってきたとおり、WHERE で絞り込んだ結果を ORDER BY で並べ替えられます。東京都に住む社員を、年齢の大きい順に取り出します。
SELECT NAME, AGE, ADDRESS FROM EMPLOYEE WHERE ADDRESS = '東京都' ORDER BY AGE DESC;
| NAME | AGE | ADDRESS |
|---|---|---|
| 高橋 翔 | 35 | 東京都 |
| 佐藤 健太 | 31 | 東京都 |
| 林檎 星飛 | 24 | 東京都 |
SELECT 文は、「FROM のテーブルから、WHERE で行を絞り込み、SELECT の列を取り出して、ORDER BY で並べる」という順で処理されると考えると、結果を予想しやすくなります。
6.9 うまくいかないときは
| 症状 | 考えられる原因と対処 |
|---|---|
| 結果が0行になる(エラーは出ない) | 条件に合う行が無いか、文字の値が1文字違っています(空白の有無、全角と半角、大文字と小文字)。= NULL と書いていないかも確認してください。 |
| 「ORA-00933: SQLコマンドが正しく終了されていません。」 | 句の順番が違う(ORDER BY の後に WHERE を書いた)か、文字の値を ' で囲んでいません。 |
| 「ORA-00920: 関係演算子が無効です。」 |
=> のように比較演算子の向きが逆です。>= と書いてください。 |
| 「ORA-00936: 式がありません。」 |
WHERE の後ろに条件が無いか、== と書いています。 |
| 「ORA-00904: "〇〇": 無効な識別子です。」 | 列名の打ち間違いです。文字の値を ' ではなく " で囲んだときにも出ます。 |
| 「ORA-01722: 数値が無効です。」 | 数の列(AGE など)を文字と比べています(AGE = 'abc')。 |
| AND と OR を使った条件の結果が思ったものと違う |
AND が先に判定されています。先に判定したいまとまりを ( ) で囲んでください。 |
ほかのエラーは、付録B「よくあるエラーと対処法」 も参考にしてください。
6.10 まとめと確認問題
まとめ
-
WHERE 条件はFROMの後、ORDER BYの前に書き、条件に合う行だけを取り出す - 比較演算子は
=・<>・>・>=・<・<=。文字の値は'で囲み、日付はDATE '2000-01-01'で書く -
ANDは両方、ORはどちらか、NOTは反転。AND と OR を混ぜるときは()で囲む -
BETWEEN 下限 AND 上限は両端を含む範囲。IN (値, …)は候補のどれか -
LIKEの%は0文字以上、_は1文字のどんな文字にも当てはまる - NULL は
IS NULL・IS NOT NULLで調べる。= NULLでは見つからない
この章で使った SQL は、付録C「SQL 早見表」 にまとめています。
確認問題
問1 総務部(部署ID 1)の社員の氏名と年齢を取り出す SQL を書いてください。
解答を見る
SELECT NAME, AGE FROM EMPLOYEE WHERE DEPT_ID = 1;
結果は 院照 心愛(27)と 鈴木 花子(29)の2行です。
問2 25歳以上30歳以下の社員を取り出す条件を、BETWEEN を使わずに書いてください。
解答を見る
WHERE AGE >= 25 AND AGE <= 30
問3 WHERE DEPT_ID = 3 OR DEPT_ID = 1 AND GENDER = 2 は、どのように解釈されますか。「開発部か総務部の、女性の社員」にするには、どう直しますか。
解答を見る
AND が先に判定されるので、「開発部の社員 または(総務部の女性)」と解釈されます。WHERE (DEPT_ID = 3 OR DEPT_ID = 1) AND GENDER = 2 と ( ) で囲みます。WHERE DEPT_ID IN (1, 3) AND GENDER = 2 とも書けます。
問4 名前に「大」を含む社員を取り出す SQL を書いてください。
解答を見る
SELECT NAME FROM EMPLOYEE WHERE NAME LIKE '%大%';
結果は 渡辺 大輔 の1行です。
問5 SELECT NAME FROM EMPLOYEE WHERE ADDRESS = NULL; は、エラーになりますか。結果は何行ですか。
解答を見る
エラーにはなりませんが、結果は0行です。NULL と等しいという比較は成り立たないためです。NULL を調べるときは IS NULL を使います。
