コマンド道場

AND / OR / NOT の使い方

AND でつなぐと、両方を満たす行だけが残る

shain社員

namebusho_idsalary
中村2530000
佐藤2720000
井上7505000
伊藤3530000

busho_id = 2 AND salary >= 500000両方を満たす行

namebusho_idsalary
中村2530000
佐藤2720000

WHERE busho_id = 2 AND salary >= 500000

  • 取り消し線= 条件に合わないので結果に出てこない行
  • 社員 18 行 → 両方を満たす行 315 行が消えます)

18 行のうち残るのは 3 行です。AND は条件を足すほど行が減り、OR は足すほど増えます。

論理演算子は `AND` `OR` `NOT` の 3 つだけです。 ただし SQL の真偽は 2 値ではなく 3 値(true / false / unknown)なので、他の言語と同じつもりで書くと結果がずれます。優先順位と、この 3 値の扱いを押さえれば事故は起きません。

この書き方が使えない製品があります そのまま使える: PostgreSQL / MySQL / MariaDB / SQLite / SQL Server / Oracle Database

未確認: IBM Db2

製品ごとの対応表(根拠つき)を見る

このページの実行結果と図は、すべて本物のデータベースに同じ SQL を流して得たものです。手で書いた「たぶんこうなる」ではありません。

01優先順位は NOT → AND → OR

結論: `NOT` がいちばん強く、次が `AND`、いちばん弱いのが `OR` です。掛け算が足し算より先に計算されるのと同じ関係です。

つまり A OR B AND C は、書いた見た目に関係なく `A OR (B AND C)` として読まれます。(A OR B) AND C のつもりで書くと、まったく違う行が返ります。

同じように NOT A AND B`(NOT A) AND B` です。NOT (A AND B) ではありません。

迷ったら括弧を書いてください。 括弧は機械のためだけでなく、あとで読む人のためでもあります。余分な括弧で怒られることはありません。

括弧を書くと、意図がそのまま形になる
  1. SELECT name, busho_id, salaryどの列を出すか
  2. FROM shainどの表を見るか
  3. WHERE (busho_id = 2 OR busho_id = 3)まず「開発か営業か」
  4. AND salary >= 600000そのうえで「60 万以上」

括弧が無いと AND が先に効き、「開発(金額を問わず)」か「営業で 60 万以上」という別の条件になります。

括弧なし(AND が先に効く)
SELECT name, busho_id, salary
FROM shain
WHERE busho_id = 2 OR busho_id = 3 AND salary >= 600000
ORDER BY shain_id;
namebusho_idsalary
佐藤2720000
田中2520000
中村2530000
小林2445050
山田3700000

5

5 行返ります。開発(busho_id = 2)の 4 人は給与に関係なく全員出ており、小林(445050)まで含まれています。書いた人の意図とは違うはずです。

括弧あり(意図どおり)
SELECT name, busho_id, salary
FROM shain
WHERE (busho_id = 2 OR busho_id = 3) AND salary >= 600000
ORDER BY shain_id;
namebusho_idsalary
佐藤2720000
山田3700000

2

2 行に減りました。「開発か営業」で、かつ「60 万以上」の人だけです。

NOT は直後の条件だけにかかる
SELECT name, busho_id, salary
FROM shain
WHERE NOT busho_id = 2 AND salary >= 600000
ORDER BY shain_id;
namebusho_idsalary
鈴木1980000
加藤5610000
山田3700000
清水4650000

4

これは「(所属が 2 でない) かつ (60 万以上)」です。NOT(A AND B) ではありません。4 行返ります。

02真理値は 3 つある

結論: SQL の条件は true / false のほかに unknown(どちらとも言えない)を返します。

NULL が絡む比較は unknown になります。この unknown を ANDOR でつないだときの規則が、SQL 特有の部分です。

  • unknown OR truetrue(片方が真と決まっているので、もう片方が分からなくても真)
  • unknown AND falsefalse(片方が偽と決まっているので、もう片方が分からなくても偽)
  • NOT unknownunknown(分からないものを否定しても分からないまま)

最後の 1 つが厄介です。false なら NOT で真に反転しますが、unknown はいくら否定しても真になりません。そして WHERE は真の行しか残さないので、その行は消えます。

3 値の計算をそのまま見る
SELECT (NULL = 1)            AS unknown_no_atai,
       (NULL = 1) OR true    AS or_true,
       (NULL = 1) AND false  AS and_false,
       NOT (NULL = 1)        AS not_shita;
unknown_no_ataior_trueand_falsenot_shita
NULLtruefalseNULL

1

NULL と表示されているのが unknown です。OR true は true に、AND false は false に確定しますが、NOT しても unknown のままなのが分かります。

03⚠️ よくある間違い:NOT で否定すると NULL の行は戻ってこない

結論: 「〜でない人」を `NOT` で書くと、その列が NULL の行がまとめて消えます。

「2025 年以降に退職した人以外」を出したくて NOT (taishoku_on > DATE '2025-01-01') と書くと、在籍中の人(退職日が NULL)が 1 人も出ません。在籍中の人の比較結果は unknown で、否定しても unknown のままだからです。

これはエラーになりません。黙って行が消えるので、件数を見ないと気づけません。

対処は 2 つです。

  • NULL の場合を明示的に足すNOT (…) OR taishoku_on IS NULL
  • そもそも NULL 判定で書く … 在籍中を出したいなら taishoku_on IS NULL と書くほうが素直です
在籍中の 16 人がまるごと消える
SELECT name, taishoku_on
FROM shain
WHERE NOT (taishoku_on > DATE '2025-01-01')
ORDER BY shain_id;
nametaishoku_on
山本2024-03-31

1

返るのは 1 行だけです。退職日が入っている 2 人のうち、条件が false になった側しか残りません。在籍中の 16 人は unknown なので落ちています。

⚠️ この書き方は SQLite / SQL Server / Oracle Database では使えません(DATE 'YYYY-MM-DD' の日付リテラル)。製品ごとの対応表

IS NULL を足すと戻ってくる
SELECT name, taishoku_on
FROM shain
WHERE NOT (taishoku_on > DATE '2025-01-01')
   OR taishoku_on IS NULL
ORDER BY shain_id;
nametaishoku_on
鈴木NULL
佐藤NULL
田中NULL
中村NULL
小林NULL
加藤NULL
吉田NULL
山田NULL

17 … うち先頭 8 行を表示

17 行になりました。在籍中の 16 人が戻り、2025 年以降に退職した人だけが除かれています。これが意図した結果です。

⚠️ この書き方は SQLite / SQL Server / Oracle Database では使えません(DATE 'YYYY-MM-DD' の日付リテラル)。製品ごとの対応表

04AND は減らし、OR は増やす

結論: `AND` で条件を足すと結果は減り、`OR` で足すと増えます。

当たり前に見えますが、条件が 3 つ 4 つと増えると分からなくなります。思ったより多いなら `OR` を疑い、少ないなら `AND` を疑う、という当たりの付け方が使えます。

件数の変化を実際に見ておくと、条件を書き間違えたときに気づきやすくなります。

条件 1 つ
SELECT count(*) AS n
FROM shain
WHERE busho_id = 2;
n
4

1

OR で足すと増える
SELECT count(*) AS n
FROM shain
WHERE busho_id = 2 OR busho_id = 3;
n
8

1

4 → 8 に増えました。

AND で足すと減る
SELECT name, salary
FROM shain
WHERE busho_id = 2 AND salary >= 500000
ORDER BY shain_id;
namesalary
佐藤720000
田中520000
中村530000

3

4 → 3 に減りました。給与が 445050 の小林だけが落ちています。

05⚠️ よくある間違い:同じ罠は NOT IN と NOT BETWEEN にもある

結論: 否定を含む述語はすべて同じ性質を持ちます。

NOT INNOT BETWEEN も、内部では比較を AND / OR でつないだものです。したがって NULL が絡むと unknown になり、その行は残りません

  • busho_id NOT IN (2, 3) … 所属が未設定の行は出ない
  • busho_id NOT BETWEEN 2 AND 3 … 同上

「〜でない」と書いたのに件数が思ったより少ないときは、まずその列に NULL があるかを疑ってください。

NOT BETWEEN でも NULL の行は消える
SELECT name, busho_id
FROM shain
WHERE busho_id NOT BETWEEN 2 AND 3
ORDER BY shain_id;
namebusho_id
鈴木1
加藤5
吉田5
井上7
木村7
清水4
斎藤4
山本4

8

8 行です。所属が 2 でも 3 でもない人は本来 10 人いますが、そのうち所属が未設定の 2 人が落ちています。

自分で打ってみる

このページの例と同じデータが入った本物のデータベースを、この場(あなたのブラウザの中)で起動できます。打った SQL がサーバーへ送られることはありません。

押すと初回だけ約 9MB を読み込みます(2 回目以降はキャッシュされます)。

解いてみる

読んだだけでは書けるようになりません。実行結果で採点します。

関連するトピック

  • 比較演算子AND / OR でつなぐ「条件そのもの」の書き方です。
  • IS NULLunknown を避けて NULL を判定する方法です。
  • WHERE 句論理演算子をいちばん使う場所です。
  • IN 述語OR をたくさん並べる代わりに使えます。

根拠(一次情報)