オラクルデータベースにおける複数テーブルの結合と副問い合わせの実践

リレーショナルデータベースにおいて、分散して格納されたデータを統合するにはテーブル結合が不可欠です。オラクルデータベースは標準SQLに加えて独自構文も歴史的にサポートしており、開発要件に応じて適切な結合手法を選択することが求められます。基本的なテーブル結合は以下のように記述します。

SELECT
  e.emp_name,
  e.salary,
  d.dept_name
FROM employee e, department d
WHERE e.dept_id = d.dept_id;

結合条件はWHERE句で定義します。複数テーブルに同名カラムが存在する場合、曖昧さを避けるため必ずテーブル名またはエイリアスで修飾する必要があります。オラクルの旧バージョン(8i以前)では結合タイプが暗黙的な構文で区別されていました。

従来の結合パターン

  • 等結合 (Equijoin): 指定カラムの値が完全に一致する行のみを抽出します。
  • 非等結合 (Non-Equijoin): 範囲演算子や不等号を用いて条件を定義します。
  • 外部結合 (Outer Join): 条件に合致しない側のレコードも結果に保持します(左外結合・右外結合)。
  • 自己結合 (Self Join): 同一テーブルを別名で複数参照し、内部的な関連データ(階層構造など)を取得します。

等結合ではAND演算子で追加フィルタを適用できます。テーブルエイリアスの活用は構文の簡潔化に加え、オプティマイザの解析効率向上にも寄与します。n個のテーブルを結合する際、最低限n-1個の結合条件が必要です。

SELECT a.emp_id, a.emp_name, a.salary, b.dept_name
FROM employee a, department b
WHERE a.dept_id = b.dept_id
  AND a.salary > 300000;

自己結合の典型的なユースケースは従業員と所属マネージャーの紐付けです。

SELECT
  w.emp_id AS staff_id,
  w.emp_name AS staff_name,
  w.manager_id,
  m.emp_name AS manager_name
FROM employee w, employee m
WHERE w.manager_id = m.emp_id;

SQL:1999準拠の明示的結合構文

オラクル9以降は標準規格に準拠した構文が採用され、結合条件とフィルタ条件が明確に分離されました。

CROSS JOINはデカルト積を生成し、結合条件を省略した従来の書き方と同義です。

SELECT e.emp_name, d.dept_name
FROM employee e
CROSS JOIN department d;

NATURAL JOINは両テーブルの同名かつ同データ型カラムを自動的に結合キーとします。この構文では結合列にテーブル修飾子を付与すると構文エラーとなるため注意が必要です。

SELECT emp_name, salary, dept_name
FROM employee
NATURAL JOIN department;

特定のカラムのみで等結合を行いたい場合はUSING句を利用します。

SELECT e.emp_name, d.dept_name, e.salary
FROM employee e
JOIN department d
USING (dept_id);

結合列の名前が異なる場合や、複雑な条件式(不等号や関数適用など)を指定する場合はON句が標準的です。

SELECT e.emp_name, d.dept_name
FROM employee e
JOIN department d
ON e.dept_id = d.dept_id;

複数テーブルの連鎖結合

3つ以上のテーブルを結合する際は、結合句を順に連結し、隣接するテーブル間の関係を個別に定義します。

SELECT e.emp_name, p.project_name, a.role_title
FROM employee e
JOIN assignment a ON e.emp_id = a.emp_id
JOIN project p ON a.project_id = p.project_id;

内部結合と外部結合の仕様整理

標準規格では、条件一致レコードのみ返すINNER JOIN(省略時のデフォルト)と、非一致レコードも保持するOUTER JOINが明確に定義されています。

  • LEFT OUTER JOIN:左表の全レコードを出力し、右表に該当データがない場合はNULL補完します。
  • RIGHT OUTER JOIN:右表の全レコードを出力し、左表の欠損値をNULLで埋めます。
  • FULL OUTER JOIN:両表の全レコードを保持し、相互に一致しない部分はNULLとして出力します。

副問い合わせ(Subquery)の設計原則

副問い合わせはメインクエリの実行前に内部的に評価され、返却された結果セットが外部条件として適用されます。

SELECT emp_name, salary
FROM employee
WHERE salary > (SELECT AVG(salary) FROM employee);

副問い合わせを設計する際は、条件値が実行時まで不定である場合に採用します。必ず丸括弧で囲み、比較演算子の右側に配置することで論理フローを明確化します。Top-N分析以外ではORDER BY句は不要であり、パフォーマンス低下の要因となります。

単一行副問い合わせ

結果が1行のみ確定する場合、スカラー比較演算子(=, >, <=, <>など)が使用可能です。

SELECT *
FROM employee
WHERE salary > (SELECT salary FROM employee WHERE emp_id = 10050);

副問い合わせが0件を返せばメインクエリも0件となります。複数行を返却した場合は「単一行サブクエリは複数行を返します」といった実行時エラーが発生するため、データモデルの整合性を事前に確認する必要があります。

複数行副問い合わせ

結果セットが複数行に及ぶ場合は、IN, ANY, ALL演算子で制御します。

  • IN:サブクエリの返すリスト内のいずれかと一致するか判定します。
  • ANY:サブクエリの任意の1値と比較(例:> ANYは返却最小値より大きい)。
  • ALL:サブクエリの全値と比較(例:> ALLは返却最大値より大きい)。
SELECT emp_name, salary
FROM employee
WHERE salary > ANY (SELECT AVG(salary) FROM employee GROUP BY dept_id);

SELECT emp_name, job_code
FROM employee
WHERE job_code IN (SELECT job_code FROM employee WHERE dept_id = 30);

Top-N分析の実装手法

ソート順に基づいて上位/下位のレコードを抽出する際は、サブクエリで順序付けを行い、外側の問い合わせでROWNUM疑似列をフィルタリングします。

SELECT emp_name, salary
FROM (
  SELECT emp_name, salary
  FROM employee
  ORDER BY salary DESC
)
WHERE ROWNUM <= 5;

タグ: Oracle SQL結合構文 副問い合わせ SQL99規格 TopN分析

5月14日 15:47 投稿