業務システムの開発やデータ分析では、1つのテーブルだけでなく「3つ以上の表」を組み合わせて情報を取得するシーンが頻繁にあります。また、単純なイコール(=)だけでなく、範囲条件などを使った「非等価結合」を使いこなせると、SQLの表現力が格段に向上します。
この記事では、Oracle SQL における複数テーブルの結合手順と、実務で役立つ非等価結合の使い方を、実機で動くサンプルコード付きで解説します。
💰 【PR】Oracleエンジニアの市場価値、調べてみませんか?
Oracleのスキルは需要が高く、特定の資格や経験を持っていると年収が大幅にアップするケースがあります。まずはIT専門のエージェントで非公開求人をチェックしてみませんか?
結論:複数テーブル結合のポイント
- 3つ以上の結合:
FROM句の後ろにJOINを続けて記述するだけで拡張可能。 - 非等価結合:結合条件に
=以外(BETWEEN,<,>など)を使用する結合。 - コツ:まずは「主となるテーブル」を決め、そこに関連するマスタを1つずつ
JOINしていく。 - 注意点:結合条件を忘れると「直積(クロス結合)」になり、データが膨れ上がるため注意が必要。
結合(JOIN)の基礎知識
表の結合とは
リレーショナルデータベースにおいて、正規化(分割)された複数のテーブルを、共通の列や条件に基づいて横に繋げる操作を指します。Oracle Databaseでは主に ANSI構文(INNER JOIN, LEFT JOIN など)が推奨されます。
非等価結合(Non-Equi Join)とは
通常、結合条件には ON A.ID = B.ID のように等価演算子(=)を使いますが、等価演算子以外を使って結合することを「非等価結合」と呼びます。 代表例が「給与がこの範囲内なら、このグレード」といった範囲結合(BETWEEN) です。
前提データ(検証用DDL/DML)
以下のSQLを実行して、検証用のテーブルとデータを作成してください。 ※ EMP(社員)、DEPT(部署)、SALGRADE(給与等級)の3つを使用します。
-- Drop tables if they exist
-- DROP TABLE EMP;
-- DROP TABLE DEPT;
-- DROP TABLE SALGRADE;
-- 1. Create DEPT table
CREATE TABLE DEPT (
DEPTNO NUMBER(2) PRIMARY KEY,
DNAME VARCHAR2(14),
LOC VARCHAR2(13)
);
INSERT INTO DEPT VALUES (10, 'ACCOUNTING', 'NEW YORK');
INSERT INTO DEPT VALUES (20, 'RESEARCH', 'DALLAS');
INSERT INTO DEPT VALUES (30, 'SALES', 'CHICAGO');
-- 2. Create EMP table
CREATE TABLE EMP (
EMPNO NUMBER(4) PRIMARY KEY,
ENAME VARCHAR2(10),
JOB VARCHAR2(9),
MGR NUMBER(4),
HIREDATE DATE,
SAL NUMBER(7, 2),
COMM NUMBER(7, 2),
DEPTNO NUMBER(2)
);
INSERT INTO EMP VALUES (7369, 'SMITH', 'CLERK', 7902, TO_DATE('1980-12-17', 'YYYY-MM-DD'), 800, NULL, 20);
INSERT INTO EMP VALUES (7499, 'ALLEN', 'SALESMAN', 7698, TO_DATE('1981-02-20', 'YYYY-MM-DD'), 1600, 300, 30);
-- 3. Create SALGRADE table
CREATE TABLE SALGRADE (
GRADE NUMBER(1),
LOSAL NUMBER(7),
HISAL NUMBER(7)
);
INSERT INTO SALGRADE VALUES (1, 700, 1200);
INSERT INTO SALGRADE VALUES (2, 1201, 1400);
INSERT INTO SALGRADE VALUES (3, 1401, 2000);
INSERT INTO SALGRADE VALUES (4, 2001, 3000);
COMMIT;
実践1:3つ以上の表を結合する
社員情報(EMP)に対し、部署名(DEPT)と給与グレード(SALGRADE)を同時に紐付けて、1つのレポートを作成します。
結合のイメージ
- EMP + DEPT:部署番号 (
DEPTNO) が一致するものを結合(等価結合) - EMP + SALGRADE:給与 (
SAL) が等級の下限 (LOSAL) と上限 (HISAL) の間にあるものを結合(非等価結合)
これらを1つのクエリにまとめます。
SELECT
E.ENAME AS Employee_Name,
E.JOB AS Job_Title,
D.DNAME AS Dept_Name,
E.SAL AS Salary,
S.GRADE AS Salary_Grade
FROM
EMP E
-- Join 1: DEPT table (Equi-join)
INNER JOIN
DEPT D ON E.DEPTNO = D.DEPTNO
-- Join 2: SALGRADE table (Non-equi-join)
INNER JOIN
SALGRADE S ON E.SAL BETWEEN S.LOSAL AND S.HISAL;
実行結果:
SQL> SELECT
2 E.ENAME AS Employee_Name,
3 E.JOB AS Job_Title,
4 D.DNAME AS Dept_Name,
5 E.SAL AS Salary,
6 S.GRADE AS Salary_Grade
7 FROM
8 EMP E
9 INNER JOIN
10 DEPT D ON E.DEPTNO = D.DEPTNO
11 INNER JOIN
12 SALGRADE S ON E.SAL BETWEEN S.LOSAL AND S.HISAL;
EMPLOYEE_N JOB_TITLE DEPT_NAME SALARY SALARY_GRADE
---------- --------- -------------- ---------- ------------
SMITH CLERK RESEARCH 800 1
ALLEN SALESMAN SALES 1600 3
解説
JOIN 句を連続して書くことで、3つでも4つでもテーブルを結合できます。Oracle Databaseのオプティマイザが最適な結合順序(駆動表など)を自動的に判断して実行します。
実践2:非等価結合(Non-Equi Join)の仕組み
先ほどの例でさりげなく登場した以下の部分が、非等価結合の実装です。
JOIN SALGRADE S ON E.SAL BETWEEN S.LOSAL AND S.HISAL
なぜ非等価結合が必要なのか?
SALGRADE 表には、EMP 表と一致する共通のID列がありません。代わりに「700〜1200の間ならグレード1」という範囲の情報を持っています。 このような場合、= では結合できないため、BETWEEN や不等号(>=, <=)を使って「値が範囲内に収まる行」を探し出して結合します。
参考:CASE式による代用(結合しない方法)
元記事では CASE 文による分類も紹介されていました。テーブル結合をせず、SQLの中で固定的に判定を行う場合は以下のように書きます。
-- Use CASE expression instead of JOIN
SELECT
E.ENAME,
E.SAL,
CASE
WHEN E.SAL > 2000 THEN 'HIGH'
WHEN E.SAL BETWEEN 1000 AND 2000 THEN 'MEDIUM'
ELSE 'LOW'
END AS SALARY_CATEGORY
FROM
EMP E;
実行結果:
SQL> SELECT
2 E.ENAME,
3 E.SAL,
4 CASE
5 WHEN E.SAL > 2000 THEN 'HIGH'
6 WHEN E.SAL BETWEEN 1000 AND 2000 THEN 'MEDIUM'
7 ELSE 'LOW'
8 END AS SALARY_CATEGORY
9 FROM
10 EMP E;
ENAME SAL SALARY
---------- ---------- ------
SMITH 800 LOW
ALLEN 1600 MEDIUM
使い分け:
- 非等価結合: 閾値やランク定義がマスタテーブル(SALGRADEなど)で管理されており、頻繁に変更される可能性がある場合。
- CASE式: 分析クエリなどで一時的にデータを分類したい場合や、マスタテーブルが存在しない場合。
💰 【PR】Oracleエンジニアの市場価値、調べてみませんか?
Oracleのスキルは需要が高く、特定の資格や経験を持っていると年収が大幅にアップするケースがあります。まずはIT専門のエージェントで非公開求人をチェックしてみませんか?
応用:データベースリンク(DB Link)先との結合
Oracle Databaseでは、ネットワーク越しにある別のデータベースのテーブルとも結合が可能です。これを実現するのが「データベースリンク(DB Link)」機能です。
データベースリンク(DB Link)とは
現在接続しているデータベースから、リモートにある別のデータベースへアクセスするための定義オブジェクトです。 テーブル名の後ろに @リンク名 を付けることで、まるでローカルにあるテーブルのように扱うことができます。
実行例:ローカルのEMP表とリモートのDEPT表を結合
例えば、本社のDB(ローカル)にある社員テーブルと、支社のDB(リモート:TOKYO_HQ)にある部署テーブルを結合する場合、以下のように記述します。
SELECT
E.ENAME,
D.DNAME
FROM
EMP E
-- Join with remote DEPT table via DB Link
INNER JOIN
DEPT@TOKYO_HQ D ON E.DEPTNO = D.DEPTNO;
注意点
- パフォーマンス: ネットワークを経由するため、大量データを結合すると処理が極端に遅くなる可能性があります。
- Driving Site: 通常、実行した側のDBにデータを集めて結合処理が行われます。リモート側のデータ量が膨大な場合は、
DRIVING_SITEヒントなどでチューニングが必要になることがあります。
トラブルシューティング
結合操作でよく発生するエラーとその対処法です。
| エラーコード | エラーメッセージ例 | 原因と対処 |
|---|---|---|
| ORA-00918 | column ambiguously defined | 結合した複数の表に同じ列名(例:DEPTNO)があり、どちらを指しているか不明確。E.DEPTNO のように表別名を付けて指定する。 |
| ORA-00904 | invalid identifier | 列名のタイプミス、またはテーブル別名(エイリアス)を付けたのに、元のテーブル名で列を指定している(例:FROM EMP E としたのに EMP.ENAME と書いた)。 |
| データ過多 | (エラーなしで大量行が返る) | 結合条件漏れによる「直積(クロス結合)」の可能性。ON 句が正しく記述されているか確認する。 |
運用・パフォーマンス上の注意
- インデックスの活用
- 結合キー(
DEPTNOなど)にインデックスがない場合、テーブル全体を読み込む「Full Table Scan」が発生し、結合処理(Hash Joinなど)が遅くなる可能性があります。外部キー列にはインデックスを作成するのが定石です。
- 結合キー(
- 非等価結合のコスト
BETWEENや不等号による結合は、等価結合に比べて処理コストが高くなりがちです。数百万件以上の大規模テーブル同士を非等価結合する場合は、処理時間に注意してください。
- ANSI構文の推奨
- 古いOracle独自の結合構文(
WHERE E.DEPTNO = D.DEPTNO)よりも、JOIN ... ON ...形式の使用を推奨します。結合条件とフィルタ条件(WHERE句)が明確に分離され、可読性が向上しミスが減ります。
- 古いOracle独自の結合構文(
FAQ:よくある質問
Q1. 4つ以上のテーブルも結合できますか?
A. はい、可能です。JOIN 句をさらに追加していくだけです。ただし、結合数が増えるほどSQLが複雑になり、パフォーマンスチューニングが難しくなる傾向があります。
Q2. 結合してもデータが表示されない行があります。なぜですか?
A. INNER JOIN(内部結合)を使用しているためです。内部結合は「両方のテーブルに条件が合致するデータがある場合」のみ表示します。 部署に所属していない社員や、グレード範囲外の給与の社員も表示したい場合は、LEFT JOIN(外部結合)を使用してください。
Q3. 結合の順序はパフォーマンスに影響しますか?
A. Oracleのオプティマイザ(CBO)が優秀なため、基本的に書く順番(FROM A JOIN B か FROM B JOIN A か)は実行計画に影響しません。人間が読んで分かりやすい順序(主テーブル → 関連マスタ)で記述しましょう。
まとめ
- 3つ以上の結合は、焦らず1つずつ
JOINを追加していけばOK。 - 非等価結合は、マスタテーブルとID以外(範囲など)で紐付けたいときに強力な武器になる。
- DB Link結合を使えば、別DBのテーブルとも透過的に結合できる(ただしネットワーク負荷に注意)。
- 列名が重複する場合は必ず表別名(エイリアス) を明記して、エラー「ORA-00918」を防ぐ。
実務では「EMP表のようなトランザクション」と「DEPT表のようなマスタ」を正しく結合できるかが基本となります。ぜひ今回のサンプルコードを手元の環境で動かして、結合の挙動を確認してみてください。
本記事は Oracle Database 19c を対象に解説します(他バージョンは画面や既定値が異なる場合があります)。
[参考]
Oracle Database SQL言語リファレンス 19c
💰 【PR】Oracleエンジニアの市場価値、調べてみませんか?
Oracleのスキルは需要が高く、特定の資格や経験を持っていると年収が大幅にアップするケースがあります。まずはIT専門のエージェントで非公開求人をチェックしてみませんか?




コメント