0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

サブクエリ(副問い合わせ)は「クエリの中に別のクエリを埋め込む」構文です。CASE式と並んでSQLの表現力を大きく広げる要素ですが、種類が多く混同しやすいため、種類ごとに整理します。

CASE式について

この後の流れ

  1. サブクエリの分類
  2. スカラサブクエリ
  3. IN/NOT INサブクエリ
  4. 相関サブクエリ
  5. EXISTS/NOT EXISTS
  6. FROM句サブクエリ(インラインビュー)とCTE
  7. まとめ

1. サブクエリの分類

種類 書く場所 返す値
スカラサブクエリ SELECT句、WHERE句 単一の値(1行1列)
IN句サブクエリ WHERE句 複数行の1列(リスト)
相関サブクエリ WHERE句、SELECT句 外側の行ごとに再評価される値
EXISTS句 WHERE句 真偽値(存在確認のみ)
FROM句サブクエリ FROM句 テーブルのような結果セット

2. スカラサブクエリ

必ず1行1列を返すサブクエリです。SELECT句に直接書けます。

SELECT
    product_name,
    price,
    (SELECT AVG(price) FROM products) AS avg_price,
    price - (SELECT AVG(price) FROM products) AS diff_from_avg
FROM products;

全体平均との差分を、各行に対して1回のクエリで算出できます。

3. IN/NOT INサブクエリ

-- 東京支店に所属する社員が担当した注文のみ抽出
SELECT * FROM orders
WHERE employee_id IN (
    SELECT employee_id FROM employees WHERE branch = '東京'
);

注意: NOT INはサブクエリの結果にNULLが1件でも含まれると、想定外に0件になります。NOT INを使う際はサブクエリ側でWHERE column IS NOT NULLを必ず付けるか、後述のNOT EXISTSを使う方が安全です。

4. 相関サブクエリ

外側のクエリの各行を参照しながら、行ごとに再評価されるサブクエリです。

-- 各カテゴリの平均価格より高い商品を抽出
SELECT p1.product_name, p1.category_id, p1.price
FROM products p1
WHERE p1.price > (
    SELECT AVG(p2.price)
    FROM products p2
    WHERE p2.category_id = p1.category_id  -- 外側のカテゴリを参照
);

IN句サブクエリとの違いは、外側の行に依存して結果が変わる点です。そのため一般的に実行コストが高く、大規模データでは注意が必要です。

5. EXISTS/NOT EXISTS

「値」ではなく「存在するかどうか」だけを見る場合はEXISTSが適しています。NULLの罠もなく、可読性・性能面で有利なケースが多いです。

-- 一度でも注文したことがある顧客
SELECT * FROM customers c
WHERE EXISTS (
    SELECT 1 FROM orders o WHERE o.customer_id = c.customer_id
);

-- 一度も注文したことがない顧客
SELECT * FROM customers c
WHERE NOT EXISTS (
    SELECT 1 FROM orders o WHERE o.customer_id = c.customer_id
);
比較項目 IN EXISTS
NULLの扱い NOT INで罠がある 影響を受けない
用途 値のリストと比較したい 存在有無だけ確認したい
可読性 シンプルな条件で読みやすい 相関条件がある場合に明確

6. FROM句サブクエリ(インラインビュー)とCTE

FROM句にサブクエリを書くと、その結果を一時的なテーブルとして扱えます。

-- FROM句サブクエリ
SELECT category_id, max_price
FROM (
    SELECT category_id, MAX(price) AS max_price
    FROM products
    GROUP BY category_id
) AS category_max
WHERE max_price >= 5000;

同じことはWITH句(CTE: 共通テーブル式)でも書けます。可読性・再利用性の観点でCTEの方が推奨されることが多いです。

WITH category_max AS (
    SELECT category_id, MAX(price) AS max_price
    FROM products
    GROUP BY category_id
)
SELECT * FROM category_max WHERE max_price >= 5000;

7. まとめ

シーン 推奨構文
単一値との比較 スカラサブクエリ
固定リストとの比較 IN(NULL混入がない前提)
行ごとの相関計算 相関サブクエリ
存在有無の判定 EXISTS / NOT EXISTS
複雑な中間結果の再利用 CTE(WITH句)

さいごに

サブクエリは「何を返すか(値・リスト・真偽値・テーブル)」で使い分けを覚えると迷いにくくなります。次回はウィンドウ関数について解説します。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?