言語
日本語
English

Caution

お使いのブラウザはJavaScriptが無効になっております。
当サイトでは検索などの処理にJavaScriptを使用しています。
より快適にご利用頂くため、JavaScriptを有効にしたうえで当サイトを閲覧することをお勧めいたします。

  1. トップページ
  2. SQL辞典
  3. 相関サブクエリ

相関サブクエリ

対応: SQL-92(1992)

外側のクエリの列を内側のサブクエリから参照するサブクエリです。外側クエリの行ごとにサブクエリが評価されるため「相関サブクエリ」と呼ばれます。

構文

外側クエリのエイリアスをサブクエリ内で参照します。

SELECT column_name
FROM table_name AS outer_alias
WHERE column_name operator (
    SELECT aggregate_function(column_name)
    FROM table_name AS inner_alias
    WHERE inner_alias.group_key = outer_alias.group_key
);

EXISTS と組み合わせた相関サブクエリです。

SELECT column_name
FROM table_name AS a
WHERE EXISTS (
    SELECT 1
    FROM other_table AS b
    WHERE b.foreign_key = a.primary_key
      AND b.condition_col = 'value'
);

構文一覧

使い方概要
WHERE句の相関サブクエリ外側の各行に対してサブクエリを評価し、条件を満たす行を返します。
SELECT句の相関サブクエリ各行に対して集計値などを動的に計算して列として追加します。
EXISTS との組み合わせ関連するデータが存在するかを行ごとに確認します。最も多い使い方です。

サンプルコード

以下の『members』テーブルを例に説明します。

members name role score 狡噛慎也 執行官 480 征陸智己 執行官 320 常守朱 監視官 620 宜野座伸元 監視官 390 4 rows in set

各メンバーのスコアが、自分の役職の平均より高いメンバーを取得します。

sample_correlated_subquery.sql
SELECT m.name, m.role, m.score
FROM members AS m
WHERE m.score > (
    SELECT AVG(sub.score)
    FROM members AS sub
    WHERE sub.role = m.role
)
ORDER BY m.role, m.score DESC;
+----------+--------+-------+
| name     | role   | score |
+----------+--------+-------+
| 狡噛慎也 | 執行官 |   480 |
| 常守朱   | 監視官 |   620 |
+----------+--------+-------+
2 rows in set

同じ役職に自分よりスコアが高いメンバーが存在するメンバーを EXISTS で取得します。『SELECT 1』の『1』に特別な意味はなく、行が存在するかどうかだけを確認するための書き方です。

sample_correlated_subquery.sql
SELECT m.name, m.role, m.score
FROM members AS m
WHERE EXISTS (
    SELECT 1
    FROM members AS sub
    WHERE sub.role = m.role
      AND sub.score > m.score
);
+------------+--------+-------+
| name       | role   | score |
+------------+--------+-------+
| 征陸智己   | 執行官 |   320 |
| 宜野座伸元 | 監視官 |   390 |
+------------+--------+-------+
2 rows in set

SELECT句で各メンバーの役職内順位を計算します。

sample_correlated_subquery.sql
SELECT
    m.name,
    m.role,
    m.score,
    (
        SELECT COUNT(*)
        FROM members AS sub
        WHERE sub.role = m.role
          AND sub.score > m.score
    ) + 1 AS rank_in_role
FROM members AS m
ORDER BY m.role, rank_in_role;
+------------+--------+-------+--------------+
| name       | role   | score | rank_in_role |
+------------+--------+-------+--------------+
| 狡噛慎也   | 執行官 |   480 |            1 |
| 征陸智己   | 執行官 |   320 |            2 |
| 常守朱     | 監視官 |   620 |            1 |
| 宜野座伸元 | 監視官 |   390 |            2 |
+------------+--------+-------+--------------+
4 rows in set

データベース別の書き方

相関サブクエリの構文は主要なデータベースで共通して使用できます。

SELECT m.name, m.role, m.score
FROM members AS m
WHERE m.score > (
    SELECT AVG(sub.score)
    FROM members AS sub
    WHERE sub.role = m.role
)
ORDER BY m.role, m.score DESC;

Oracle ではテーブルエイリアスに『AS』キーワードが使えません。エイリアスを付ける際は『AS』を省略して記述します。

SELECT m.name, m.role, m.score
FROM members m
WHERE m.score > (
    SELECT AVG(sub.score)
    FROM members sub
    WHERE sub.role = m.role
)
ORDER BY m.role, m.score DESC;

概要

相関サブクエリは外側クエリの各行に対してサブクエリが1回ずつ実行されます。外側クエリがN行あればサブクエリもN回実行されるため、大量データに対してそのまま使うとパフォーマンスが悪化します。同じ結果はウィンドウ関数(『OVER / PARTITION BY』)や JOIN で書き直せることが多く、大規模テーブルでは書き換えを検討してください。

EXISTS との組み合わせはサブクエリが1行見つかった時点で評価を打ち切るため、IN より効率よく動作します。SELECT句の相関サブクエリは可読性が高い反面、実行コストが大きいため注意が必要です。

サブクエリの基本は『サブクエリ(スカラー・行)』を、EXISTS の使い方は『IN / EXISTS』を参照してください。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。