AND / OR / NOT の使い方
shain社員
| name | busho_id | salary |
|---|---|---|
| 中村 | 2 | 530000 |
| 佐藤 | 2 | 720000 |
| 井上 | 7 | 505000✕ |
| 伊藤 | 3 | 530000✕ |
| … | ||
busho_id = 2 AND salary >= 500000両方を満たす行
| name | busho_id | salary |
|---|---|---|
| 中村 | 2 | 530000 |
| 佐藤 | 2 | 720000 |
| … | ||
WHERE busho_id = 2 AND salary >= 500000
- 取り消し線= 条件に合わないので結果に出てこない行
- 社員 18 行 → 両方を満たす行 3 行(15 行が消えます)
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) ではありません。
迷ったら括弧を書いてください。 括弧は機械のためだけでなく、あとで読む人のためでもあります。余分な括弧で怒られることはありません。
SELECT name, busho_id, salaryどの列を出すかFROM shainどの表を見るかWHERE (busho_id = 2 OR busho_id = 3)まず「開発か営業か」AND salary >= 600000そのうえで「60 万以上」
括弧が無いと AND が先に効き、「開発(金額を問わず)」か「営業で 60 万以上」という別の条件になります。
SELECT name, busho_id, salary
FROM shain
WHERE busho_id = 2 OR busho_id = 3 AND salary >= 600000
ORDER BY shain_id;| name | busho_id | salary |
|---|---|---|
| 佐藤 | 2 | 720000 |
| 田中 | 2 | 520000 |
| 中村 | 2 | 530000 |
| 小林 | 2 | 445050 |
| 山田 | 3 | 700000 |
(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;| name | busho_id | salary |
|---|---|---|
| 佐藤 | 2 | 720000 |
| 山田 | 3 | 700000 |
(2 行)
2 行に減りました。「開発か営業」で、かつ「60 万以上」の人だけです。
SELECT name, busho_id, salary
FROM shain
WHERE NOT busho_id = 2 AND salary >= 600000
ORDER BY shain_id;| name | busho_id | salary |
|---|---|---|
| 鈴木 | 1 | 980000 |
| 加藤 | 5 | 610000 |
| 山田 | 3 | 700000 |
| 清水 | 4 | 650000 |
(4 行)
これは「(所属が 2 でない) かつ (60 万以上)」です。NOT(A AND B) ではありません。4 行返ります。
02真理値は 3 つある
結論: SQL の条件は true / false のほかに unknown(どちらとも言えない)を返します。
NULL が絡む比較は unknown になります。この unknown を AND や OR でつないだときの規則が、SQL 特有の部分です。
unknown OR true→ true(片方が真と決まっているので、もう片方が分からなくても真)unknown AND false→ false(片方が偽と決まっているので、もう片方が分からなくても偽)NOT unknown→ unknown(分からないものを否定しても分からないまま)
最後の 1 つが厄介です。false なら NOT で真に反転しますが、unknown はいくら否定しても真になりません。そして WHERE は真の行しか残さないので、その行は消えます。
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_atai | or_true | and_false | not_shita |
|---|---|---|---|
| NULL | true | false | NULL |
(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と書くほうが素直です
SELECT name, taishoku_on
FROM shain
WHERE NOT (taishoku_on > DATE '2025-01-01')
ORDER BY shain_id;| name | taishoku_on |
|---|---|
| 山本 | 2024-03-31 |
(1 行)
返るのは 1 行だけです。退職日が入っている 2 人のうち、条件が false になった側しか残りません。在籍中の 16 人は unknown なので落ちています。
⚠️ この書き方は SQLite / SQL Server / Oracle Database では使えません(DATE 'YYYY-MM-DD' の日付リテラル)。製品ごとの対応表
SELECT name, taishoku_on
FROM shain
WHERE NOT (taishoku_on > DATE '2025-01-01')
OR taishoku_on IS NULL
ORDER BY shain_id;| name | taishoku_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` を疑う、という当たりの付け方が使えます。
件数の変化を実際に見ておくと、条件を書き間違えたときに気づきやすくなります。
SELECT count(*) AS n
FROM shain
WHERE busho_id = 2;| n |
|---|
| 4 |
(1 行)
SELECT count(*) AS n
FROM shain
WHERE busho_id = 2 OR busho_id = 3;| n |
|---|
| 8 |
(1 行)
4 → 8 に増えました。
SELECT name, salary
FROM shain
WHERE busho_id = 2 AND salary >= 500000
ORDER BY shain_id;| name | salary |
|---|---|
| 佐藤 | 720000 |
| 田中 | 520000 |
| 中村 | 530000 |
(3 行)
4 → 3 に減りました。給与が 445050 の小林だけが落ちています。
05⚠️ よくある間違い:同じ罠は NOT IN と NOT BETWEEN にもある
結論: 否定を含む述語はすべて同じ性質を持ちます。
NOT IN も NOT BETWEEN も、内部では比較を AND / OR でつないだものです。したがって NULL が絡むと unknown になり、その行は残りません。
busho_id NOT IN (2, 3)… 所属が未設定の行は出ないbusho_id NOT BETWEEN 2 AND 3… 同上
「〜でない」と書いたのに件数が思ったより少ないときは、まずその列に NULL があるかを疑ってください。
SELECT name, busho_id
FROM shain
WHERE busho_id NOT BETWEEN 2 AND 3
ORDER BY shain_id;| name | busho_id |
|---|---|
| 鈴木 | 1 |
| 加藤 | 5 |
| 吉田 | 5 |
| 井上 | 7 |
| 木村 | 7 |
| 清水 | 4 |
| 斎藤 | 4 |
| 山本 | 4 |
(8 行)
8 行です。所属が 2 でも 3 でもない人は本来 10 人いますが、そのうち所属が未設定の 2 人が落ちています。
自分で打ってみる
このページの例と同じデータが入った本物のデータベースを、この場(あなたのブラウザの中)で起動できます。打った SQL がサーバーへ送られることはありません。
押すと初回だけ約 9MB を読み込みます(2 回目以降はキャッシュされます)。
解いてみる
読んだだけでは書けるようになりません。実行結果で採点します。
関連するトピック
根拠(一次情報)
- PostgreSQL 18 マニュアル: 論理演算子(3 値論理の真理値表)一次情報・確認 2026-08-03
- PostgreSQL 18 マニュアル: 演算子の優先順位一次情報・確認 2026-08-03
- MySQL 8.4 リファレンスマニュアル: 演算子の優先順位一次情報・確認 2026-08-03