B L O G

  1. TOP
  2. BLOG
  3. はじめてのSQL【中級編:述語について②】
プログラミング
2025.06.02

はじめてのSQL【中級編:述語について②】

こんにちは。

スタッフブログ担当の岩でございます。

前回の記事では「LIKE」、「BETWEEN」、「IS NULL」、「IS NOT NULL」という述語について説明いたしました。

はじめてのSQL【中級編:述語について①】

今回は、「IN」、「EXISTS」という述語について説明いたします。

今回はShopテーブルとTenpoShohinテーブルを使って説明します。

shohin_id
(商品ID)
shohin_mei
(商品名)
shohin_bunrui
(商品分類)
hanbai_tanka
(販売単価)
shiire_tanka
(仕入単価)
torokubi
(登録日)
0001ボールペン事務用品100502020-10-20
0002おろしがねキッチン用品5003502020-09-07
0003フォークキッチン用品10030
0004圧力鍋キッチン用品500010002020-04-25
0005包丁キッチン用品80002020-07-05
0006カッターシャツ衣類300015002020-06-11
0007穴あけパンチ事務用品4002402020-11-27
0008Tシャツ衣類15002020-03-13
Shopテーブル
tenpo_id
(店舗ID)
tenpo_mei
(店舗名)
shohin_id
(商品ID)
suryo
(数量)
A東京000130
A東京000250
A東京000315
B名古屋000230
B名古屋0004120
B名古屋000520
C大阪000450
C大阪000690
C大阪000770
TenpoShohinテーブル

   

IN述語

IN述語はORを省略して記述することができます。

まず、ORを使ってShopテーブルから「仕入単価が50円、240円、350円」のデータを選択しましょう。

SELECT shohin_id, shohin_mei, shiire_tanka
FROM Shop
WHERE shiire_tanka = 50
OR    shiire_tanka = 240
OR    shiire_tanka = 350;
shohin_id
(商品ID)
shohin_mei
(商品名)
shiire_tanka
(仕入単価)
0001ボールペン50
0002おろしがね350
0007穴あけパンチ240
ORの検索結果

この書き方の欠点は、選択対象としたい値が増えるにつれてSQLもどんどん長くなってしまうことです。

こんなときはIN述語を使うとすっきりまとまります。

SELECT shohin_id, shohin_mei, shiire_tanka
FROM Shop
WHERE shiire_tanka IN (50, 240, 350);

反対に「仕入単価が50円、240円、350円以外」のデータを選択したいときは、

否定形の「NOT IN」を使います。

SELECT shohin_id, shohin_mei, shiire_tanka
FROM Shop
WHERE shiire_tanka NOT IN (50, 240, 350);
shohin_id
(商品ID)
shohin_mei
(商品名)
shiire_tanka
(仕入単価)
0003フォーク30
0004圧力鍋1000
0006カッターシャツ1500
NOT INの検索結果

INとNOT INどちらの場合でも、NULLを選択することはできないことに注意してください。

INとNOT INどちらの結果にも、仕入単価がNULLのデータは選択されていません。

NULLはあくまでIS NULL、IS NOT NULLで判別するのが決まりです。

   

INとサブクエリ

IN述語、NOT IN述語は、引数にサブクエリを指定することができます。

実際の使い方をTenpoShohinテーブルを使ってみてみましょう。

例1.大阪店(tenpo_id = ‘C’)に置いている商品(shohin_id)の販売単価(hanbai_tanka)を求める

SELECT shohin_id, shohin_mei, hanbai_tanka
FROM Shohin
WHERE shohin_id IN (
        SELECT shohin_id
        FROM TenpoShohin
        WHERE tenpo_id = 'C'
);
shohin_id
(商品ID)
shohin_mei
(商品名)
hanbai_tanka
(販売単価)
0004圧力鍋5000
0006カッターシャツ3000
0007穴あけパンチ400
大阪店に置いている商品検索結果

この例1.の問題を解くためには2つのステップがあります。

1.TempoShohinテーブルから大阪店(tenpo_id = ‘C’)が持っている商品(shohin_id)を選択する。

2.Shopテーブルから 1. で選択した商品(shohin_id)のみ販売単価(hanbai_tanka)を選択する。

1つ目のステップにあたるのがIN述語の引数で指定しているサブクエリです。

サブクエリは内側から実行されていくので、一番最初に実行されるのは以下の部分です。

SELECT shohin_id
FROM TenpoShohin
WHERE tenpo_id = 'C';
shohin_id(商品ID)
0004
0006
0007
サブクエリの実行結果

   

サブクエリを展開したSQL文は以下の通りです。

SELECT shohin_id, shohin_mei, hanbai_tanka
FROM Shohin
WHERE shohin_id IN ('0004','0006','0007');

展開した形でSQLを書けるなら、サブクエリを使う必要はないのではないか?

と思われるかもしれませんが、

「TenpoShohinテーブルのデータが絶対に変更されない。」という条件が

あればサブクエリを使う必要はありません。

実際には各店舗で扱う商品は変わっていくでしょうから、TenpoShohinテーブル内の大阪店の扱う

商品も変化していくと思います。

その場合、サブクエリを使わないと商品が変更される度に、SQL文を修正しなければなりません。

一方、サブクエリを使ってSQL文を作成しておけば、データがどれだけ変更されても

ずっと同じSQL文を使い続けることができます。

このように、データの変更に強いという利点を持つプログラムを

「保守性に優れる」、「メンテナンスフリー」と呼びます。

   

EXISTS述語

実はEXISTSを使わなくてもINやNOT INでほぼ代用できます。

しかし、完全に代用できるわけではありません。

EXISTS述語は「条件に合致するレコードの存在有無を調べること」です。

条件に合致するレコードが存在すれば真(TRUE)、存在しなければ偽(FALSE)を返します。

INとサブクエリで求めたものと同じ

「大阪店(tenpo_id = ‘C’)に置いている商品(shohin_id)の販売単価(hanbai_tanka)」

をEXISTSを使って求めてみましょう。

SELECT shohin_id, shohin_mei, hanbai_tanka
FROM Shop AS S
WHERE EXISTS (
        SELECT 1
        FROM TenpoShohin AS TS
        WHERE TS.tenpo_id = 'C'
        AND   TS.shohin_id = S.shohin_id
);
shohin_id
(商品ID)
shohin_mei
(商品名)
hanbai_tanka
(販売単価)
0004圧力鍋5000
0006カッターシャツ3000
0007穴あけパンチ400
EXISTSの検索結果

EXISTSは必ず右側に相関サブクエリを記述します。

今回のSQL文でも「TS.shohin_id = S.shohin_id」という風にShopテーブルとTenpoShohinテーブルを結合しています。

また、サブクエリのSELECT部分で「SELECT 1」と記述しています。

これはどの行も選択していませんが、EXISTSはレコードの存在有無しか確認しないため、

どのような行を選択していても一切関係ありません。

そのため、以下のような書き方をしても結果は変わりません。

SELECT shohin_id, shohin_mei, hanbai_tanka
FROM Shop AS S
WHERE EXISTS (
        SELECT *
        FROM TenpoShohin AS TS
        WHERE TS.tenpo_id = 'C'
        AND   TS.shohin_id = S.shohin_id
);

   

INをEXISTSで書き換えられたように、NOT INを「NOT EXISTS」で書き換えることも可能です。

「東京店(tenpo_id = ‘A’)に置いている商品(shohin_id)以外の販売単価(hanbai_tanka)」

をNOT EXISTSを使って記述します。

SELECT shohin_id, shohin_mei, hanbai_tanka
FROM Shop AS S
WHERE NOT EXISTS (
        SELECT 1
        FROM TenpoShohin AS TS
        WHERE TS.tenpo_id = 'A'
        AND   TS.Shohin_id = S.Shohin_id
);
shohin_id
(商品ID)
shohin_mei
(商品名)
hanbai_tanka
(販売単価)
0004圧力鍋5000
0005包丁8000
0006カッターシャツ3000
0007穴あけパンチ400
0008Tシャツ1500
NOT EXISTSの検索結果

まとめ

今回は「IN」と「EXISTS」を一緒に説明いたしました。

「IN」の方が分かりやすいなと感じる方が多いのではないでしょうか。

しかし、「EXISTS」には「IN」にはない便利さがあり、このふたつは厳密に同値ではないので

どちらの述語もマスターしていただければと思います。

最後までお読みいただきありがとうございました。