【SQL】NOT・AND・ORの優先順位とNULL
NOT演算子
NOTは単独では使わず、他の検索条件と組み合わせて使う
1000円以上の場合
SELECT shohin_mei, shohin_bunrui, hanbai_tanka
FROM Shohin
WHERE hanbai_tanka >= 1000;
shohin_mei | shohin_bunrui | hanbai_tanka
----------------+---------------+--------------
Tシャツ | 衣服 | 1000
カッターシャツ | 衣服 | 4000
包丁 | キッチン用品 | 3000
圧力鍋 | キッチン用品 | 6800
NOT演算子で否定する場合
SELECT shohin_mei, shohin_bunrui, hanbai_tanka
FROM Shohin
WHERE NOT hanbai_tanka >= 1000;
shohin_mei | shohin_bunrui | hanbai_tanka
--------------+---------------+--------------
穴あけパンチ | 事務用品 | 500
フォーク | キッチン用品 | 500
おろしがね | キッチン用品 | 880
ボールペン | 事務用品 | 100
「1000円以上」という条件が否定され、「1000円未満」の行が選択される。 つまり、以下のコードと同じ結果になる。
SELECT shohin_mei, shohin_bunrui, hanbai_tanka
FROM Shohin
WHERE hanbai_tanka < 1000;
shohin_mei | shohin_bunrui | hanbai_tanka
--------------+---------------+--------------
穴あけパンチ | 事務用品 | 500
フォーク | キッチン用品 | 500
おろしがね | キッチン用品 | 880
ボールペン | 事務用品 | 100
<>で否定した場合
SELECT shohin_mei, shohin_bunrui, hanbai_tanka
FROM Shohin
WHERE hanbai_tanka <> 1000;
shohin_mei | shohin_bunrui | hanbai_tanka
----------------+---------------+--------------
穴あけパンチ | 事務用品 | 500
カッターシャツ | 衣服 | 4000
包丁 | キッチン用品 | 3000
圧力鍋 | キッチン用品 | 6800
フォーク | キッチン用品 | 500
おろしがね | キッチン用品 | 880
ボールペン | 事務用品 | 100
1000円以外の行が選択される。
【注意】NULLを含む場合
例:仕入単価はNULLを含んでいる
/* 前提 */
SELECT shohin_mei, shohin_bunrui, shiire_tanka
FROM Shohin;
shohin_mei | shohin_bunrui | shiire_tanka
----------------+---------------+--------------
Tシャツ | 衣服 | 500
穴あけパンチ | 事務用品 | 320
カッターシャツ | 衣服 | 2800
包丁 | キッチン用品 | 2800
圧力鍋 | キッチン用品 | 5000
フォーク | キッチン用品 | -- NULL
おろしがね | キッチン用品 | 790
ボールペン | 事務用品 | -- NULL
1000円以上の場合
SELECT shohin_mei, shohin_bunrui, shiire_tanka
FROM Shohin
WHERE shiire_tanka >= 1000;
shohin_mei | shohin_bunrui | shiire_tanka
----------------+---------------+--------------
カッターシャツ | 衣服 | 2800
包丁 | キッチン用品 | 2800
圧力鍋 | キッチン用品 | 5000
NOT演算子で否定する場合
SELECT shohin_mei, shohin_bunrui, shiire_tanka
FROM Shohin
WHERE NOT shiire_tanka >= 1000;
shohin_mei | shohin_bunrui | shiire_tanka
--------------+---------------+--------------
Tシャツ | 衣服 | 500
穴あけパンチ | 事務用品 | 320
おろしがね | キッチン用品 | 790
NULLの行がどちらにも現れない
/* 上記のどちらのSELECT文でも出てこない2行 */
shohin_mei | shohin_bunrui | shiire_tanka
----------------+---------------+--------------
フォーク | キッチン用品 | -- NULL
ボールペン | 事務用品 | -- NULL
- NULL >= 1000 → 不明なので真偽の判断が不可能
NOT不明 → 「不明」なものをNOTでひっくり返すことは不可能(真にならない)WHEREは「真」のときだけ通るので、1.2.のどちらでも落ちる
NULLも拾いたい場合はOR shiire_tanka IS NULL
/* 1000円以上またはNULLの場合 */
SELECT shohin_mei, shohin_bunrui, shiire_tanka
FROM Shohin
WHERE shiire_tanka >= 1000
OR shiire_tanka IS NULL;
shohin_mei | shohin_bunrui | shiire_tanka
----------------+---------------+--------------
カッターシャツ | 衣服 | 2800
包丁 | キッチン用品 | 2800
圧力鍋 | キッチン用品 | 5000
フォーク | キッチン用品 |
ボールペン | 事務用品 |
/* 1000円未満またはNULLの場合 */
SELECT shohin_mei, shohin_bunrui, shiire_tanka
FROM Shohin
WHERE (NOT shiire_tanka >= 1000)
OR shiire_tanka IS NULL;
shohin_mei | shohin_bunrui | shiire_tanka
--------------+---------------+--------------
Tシャツ | 衣服 | 500
穴あけパンチ | 事務用品 | 320
フォーク | キッチン用品 |
おろしがね | キッチン用品 | 790
ボールペン | 事務用品 |
AND演算子
複数の条件をすべて満たす
SELECT shohin_mei, shiire_tanka
FROM Shohin
WHERE shohin_bunrui = 'キッチン用品'
AND hanbai_tanka >= 3000;
/* キッチン用品かつ販売単価3000円以上 */
shohin_mei | shiire_tanka
------------+--------------
包丁 | 2800
圧力鍋 | 5000
OR演算子
複数の条件のいずれかを満たす
SELECT shohin_mei, shiire_tanka
FROM Shohin
WHERE shohin_bunrui = 'キッチン用品'
OR hanbai_tanka >= 3000;
/* キッチン用品または販売単価3000円以上 */
shohin_mei | shiire_tanka
----------------+--------------
カッターシャツ | 2800
包丁 | 2800
圧力鍋 | 5000
フォーク |
おろしがね | 790
優先順位付けと()
【条件】事務用品かつ、登録日は2009-09-11または2009-09-20
/* NG */
SELECT shohin_mei, shohin_bunrui, torokubi
FROM Shohin
WHERE shohin_bunrui = '事務用品'
AND torokubi = '2009-09-11'
OR torokubi = '2009-09-20';
shohin_mei | shohin_bunrui | torokubi
--------------+---------------+------------
Tシャツ | 衣服 | 2009-09-20
穴あけパンチ | 事務用品 | 2009-09-11
包丁 | キッチン用品 | 2009-09-20
フォーク | キッチン用品 | 2009-09-20
- 事務用品以外も選択されている
- 「事務用品、かつ登録日が2009-09-11」
「または登録日が2009-09-20」と解釈されている
OR演算子よりAND演算子のほうが優先される
SELECT shohin_mei, shohin_bunrui, torokubi
FROM Shohin
WHERE shohin_bunrui = '事務用品'
/* OR演算子とその両辺を()で囲む */
AND (torokubi = '2009-09-11'
OR torokubi = '2009-09-20');
shohin_mei | shohin_bunrui | torokubi
--------------+---------------+------------
穴あけパンチ | 事務用品 | 2009-09-11
AND演算子よりもOR演算子を優先させたい場合は()で囲む。
ちなみに、NOT > AND > OR の順で優先順位がつけられる
安全策:NOT、AND、ORが混ざったら、必ず()をつける
参考書籍:ミック『SQL 第2版 ゼロからはじめるデータベース操作』(翔泳社)