【SQL – Oracle】複数の表の結合について

【SQL – Oracle】複数の表の結合について

結合とは

 結合とは、複数の表を関連付けてデータを取り出す機能です。この機能を使用すると、下図のようにEMPLOYEES表(社員表)と、DEPARTMENTS表(部門表)を結合して、社員情報と部門情報を一緒に取り出すことができます。

▶ GROUP BY句を使用したSELECT文

 一般的なリレーショナルデータベースの多くは、核データを属性のグループごとに別々の表に格納しています。例えば、上記のサンプル表のように、社員に関数る情報(社員番号や社員名、給与、部門番号などの属性)はEMPLOYEES表に、部門に関する情報(部門番号や部門名などの属性)はDEPARTMENTS表に格納するといった具合です。そのため、「社員名とその社員の所属部門名」のように、複数の表に分散しているデータを1つの」結果として取り出したい場合は、SQL文で関連する表を「結合」することが必要になります。

※データベースの設計時に、「正規化」という手法を用いて、各データの属性を基にデータの分類や重複データの排除などを行い、更新処理を効率よく実行できるようにデータ構造を最適化しています。

■ 基本的な表の結合方法
 複数の表を結合する方法はいくつかありますが、もっともシンプルな方法は、FROM句に結合する表の名前を「,」(カンマ)で区切って指定して表を結合する方法です。FROM句に複数の表明を指定すると、指定した表が結合されてデータが取り出されます。
 以下の例では、EMPLOYEES表とDEPARTMENTS表を結合して、EMPNO列、ENAME列、DNAME列の値を表示しています。

▶ 2つの表の結合

SQL> SELECT empno, ename, dname
 2  FROM employees, departments;
 
EMPNO  ENAME       DNAME
-----  ---------  ----------
1001   佐藤        管理
1002   鈴木        管理
1003   高橋        管理
(省略)
1013   山田        管理
1014   佐々木      管理
1001   佐藤        研究開発
1002   鈴木        研究開発
1003   高橋        研究開発
(省略)
1012   吉田        財務
1013   山田        財務
1014   佐々木      財務

56行が選択されました。

 なお、上記の実行結果を見るとわかりますが、この方法では結合した表の全ての組み合わせが表示されます(56件 = EMPLOYEES表の14件 x DEPARTMENTS表の4件)。そのため、中には「所属部門が管理部(部門番号:10)の佐藤さん」と「研究開発部門(部門番号:20)」を結合した「意味のないデータ」も含まれいます。

■ 表接頭辞を使用した列名の修飾
 上記の例では、SELECT句に指定しているすべての列が、結合する表のいずれかにしか存在しない列であるため正常に実行できましたが、結合する表の両方に存在する列をSELECT句に指定するとエラーになります。
 以下の例では、EMPLOYEES表とDEPARTMENTS表の両方にあるDEPTNO列をSELECT句に指定して、表を結合しようとしています。しかし、以下のSQL文では、どちらの表からDEPTNO列の値を取り出せばよいのかを、Oracleサーバーが判断できないため、「ORA-00918: 列の定義が未確定です。」というエラーが発生しています。

▶ あいまいな列の指定

SQL> SELECT empno, ename, dname, deptno
 2  FROM employees, departments;
select empno, ename, dname, deptno
                        *
行1でエラーが発生しました。:
ORA-00918: 列の定義が未確定です。 

 このような場合は、列名に「表接頭辞」をつけることで明示的に「どの表の、どの列」という形で指定し、列名のあいまいさを回避する必要があります。

▶ 表接頭辞を使用した列名の修飾
  表名.列名
    ※この形式の”表名.”の部分を「表接頭辞」といいます。

 以下の例では、DEPTNO列に表接頭辞「EMPLOYEES.」を付けて、SQL文を実行しています、表接頭辞をつけることで、列名のあいまいさが回避されるため、正常に実行できています。

▶ 表接頭辞を使用した列名の修飾(1)

SQL> SELECT empno, ename, dname, employees.deptno
 2  FROM employees, departments;

EMPNO   ENAME    DNAME        DEPTNO
------ -------  -----------  --------
1001    佐藤      管理         10
1002    鈴木      管理         20
1003    高橋      管理         30
(省略)
1013    山田      財務         20
1014    佐々木    財務         10

56行が選択されました。

 なお、表接頭辞は結合する表に重複する列名がない場合でも使用できます。表接頭辞を使用するれば、OracleサーバーがSQL文の構文を解析する際に列名の重複の有無をチェックする必要がなくなるため、わずかですがSQL文のパフォーマンスが向上します。また、表接頭辞を付けることでSELECT文がわかりやすくなるというメリットもあります。

▶ 表接頭辞を使用した列名の修飾(2)

SQL> SELECT employees.empno, employees.ename,
            employees.dname, employees.deptno
 2  FROM employees, departments;

EMPNO   ENAME    DNAME        DEPTNO
------ -------  -----------  --------
1001    佐藤      管理         10
1002    鈴木      管理         20
1003    高橋      管理         30
(省略)
1013    山田      財務         20
1014    佐々木    財務         10

56行が選択されました。

■ 表別名の使用
 SELECT句に指定できる「列別名」と同様に、FROM句では「表別名」を指定できます。
 表別名は、FROM句に指定した表名の後ろに1つ以上のスペースを入れて指定します。なお、列別名を指定する際に使用できる「ASキーワード」は、表別名では使用できないので注意してください。

▶ 表別名の指定
  FROM 表名 表別名

 また、表別名を指定する際は以下の点を考慮してください。
  ・表別名は30バイト以下
  ・一般的に表別名にはわかりやすく、短い名前を指定する
  ・表接頭辞に短い表別名を使用するとSQL文が短くなるため、メモリーの使用量を削減できる
  ・表別名は、表別名を指定したSQL文でのみ有効

 以下の例では、結合する各表に表別名(「e」と「d」)を指定しています。表別名を使用していないSQL文『表接頭辞を使用した列名の修飾(2)』と比べ、SQL文全体が短く、わかりやすくなっていることがわかります。

▶ 表別名を使用した表の結合

SQL> SELECT e.empno, e.ename, d.dname, e.deptno
 2  FROM employees e, departments d;

EMPNO   ENAME    DNAME        DEPTNO
------ -------  -----------  --------
1001    佐藤      管理         10
1002    鈴木      管理         20
1003    高橋      管理         30
(省略)
1013    山田      財務         20
1014    佐々木    財務         10

56行が選択されました。

 なお、表別名を指定すると、SQL文全体で元の表明は無効になるので注意してください。次の例では、表接頭辞に元の表名を使用しているため、「ORA-00904: 無効な識別子です。」というエラーが発生しています。表別名を指定した場合は、表接頭辞にも必ず表別名を使用してください。

▶ 表別名を使用した際のエラー

SQL> SELECT employees.empno, employees.ename,
            employees.dname, employees.deptno
 2  FROM employees, departments;
                   *
行1でエラーが発生しました。:
ORA-00904: "EMPLOYEES"."DEPTNO": 無効な識別子です。

まとめ

▶ 結合する表に重複する列名がある場合は、表接頭辞を指定する
▶ 表接頭辞を使用すると、SQL文のパフォーマンスが向上する
▶ 表接頭辞には表別名を指定できる
▶ 表別名を指定すると、SQL文全体で元の表名は無効になる

コメントを残す