データベース初心者必見!入門編その6〜複数のテーブルから取得する〜
2015/07/27
はじめに
今回は、入門編その1、入門編その2、入門編その3、入門編その4、入門編その5の続きです。
今回は複数のテーブルからデータを取得する方法について紹介いたします。
複数のテーブルからデータを取得する
これまでは、一つのテーブルに対するSELECT文、射影、選択の操作を行ってきました。
しかし、リレーショナルデータベースの特性上、複数のテーブルからデータを取得する必要が数多くあります。リレーショナルデータベースでは、テーブルを作成するときに正規化と呼ばれる手法がとられます。テーブルの作成や正規化の詳細については後述しますが、正規化されて作成されたテーブルのひとつひとつは可能な限りシンプルな形に集約されて作られています。そして、テーブル同士を外部キーによって関連付けてデータを表現します。
たとえば、これまでも使用してきたgoodsテーブルのctg_id列は、goods(商品)のカテゴリ番号を表すものです。その番号のカテゴリーがどういう名前であるかは、別に作られたcategoryテーブルのctg_name列を見ればわかるというように構成されています。
このようにリレーショナルデータベースではテーブルが関連付けられて構成されていますが、場合によっては次に画面のように、結果セットの中に「商品の名前」と「カテゴリーの名前」を含んだものを取得したいことがあります。
この操作を実現するためには。SELECT文でテーブルを結合します。 ここからはテーブルとテーブルを連結させて問い合わせSELECT文、結合について紹介していきます。
クロス結合
クロス結合を行うにはCROSS JOIN句を使います。
[shell]SELECT * FROM goods WHERE gds_id=1 CROSS JOIN category[/shell]
実行結果
goodsテーブルのctg_id=1の行に、categoryテーブルの全行が結合されて表示されました。 これはクロス結合と呼ばれる結合の方法です。クロス結合では、テーブル同士の行の可能な限りの組み合わせで結果セットを取得することができますが、これはたいていの場合意味のないものとなってしまいます。実用性のある結合方法ではありません。 今回も結合自体はうまくいきましたが、利用しやすい結果を得ることはできませんでした。 クロス結合では、SELECT文のFROM句に結合したいテーブル名を「,」で区切って列挙して記述することもできます。
[shell]SELECT * FROM goods,category WHERE gds_id=1[/shell]
実行結果
前回と同じ結果を得ることができました。
先ほどのクロス結合では、テーブルの結合をおこなうことができましたが、抽出された結果セットは利用しやすいものではありませんでした。テーブルを結合するときには、意図した結果セットをえるために結合条件を指定することができます
結合には、クロス結合の他にもいくつかの形式があります。
表「結合の形式」
形式 | 説明 |
クロス結合 | 行の可能な限りの組み合わせで結果セットを取得する |
内部結合 | テーブルから結合条件に一致するデータを取得する |
外部結合 | 結合条件に一致するデータに加えて、指定された一方のすべてのデータを取得する |
内部結合
では、内部結合から紹介します。
内部結合は2つのテーブルで値の等しい列をひとつの行として抽出するものです。どの列を結合に使用するかの条件を記述していますが、等しい値がない行は無視されて、結果セットには抽出されません。
内部結合にはINNER JOIN句とON句を用いて次のように記述します。
[shell]SELECT gds_name,ctg_name FROM goods INNER JOIN category ON goods.ctg_id = category.ctg_id[/shell]
実行結果
結果としてgoodsテーブルのgds_name列とcategoryテーブルのctg_name列をひとつの結果セットの中に抽出することができました。また、他方のテーブルのctg_id列に等しい値がない行は無視され、結果セットに存在しません。(goodsテーブルの「革靴」の行とcategoryテーブルの「文具」「玩具」の行は無視されているということ)
これが内部結合です。
INNER JOIN句では、結合条件をON句に記述します。次の部分です。 「ON goods. ctg_id = category.ctg_id」 ctg_id列は両方のテーブルに存在する列なので、「テーブル名.列名」とすることで、いずれのテーブルの列であるかを明示しています。 他方のテーブルに存在しないテーブル固有の列名であれば修飾する必要はありません。
列名をテーブル名で修飾することは、両方のテーブルに同名の列が存在する場合に必要となるますが、これは結合条件で記述する場合に限りません。射影によって名前が重複する列を指定する場合にもテーブル名での修飾が必要となります。
[shell]SELECT gds_name,ctg_name,goods.ctg_id FROM goods INNER JOIN category ON goods.ctg_id = category.ctg_id[/shell]
SELECTの後の列名リストでgoodsテーブルとcategoryテーブルの両方に存在するctg_id列を記述しました。テーブル名で修飾しています。
また、列別名と同じようにテーブルを別名をつけることができます。テーブル名が長い場合には別名をつけておくと、列名をテーブル名で修飾するときには便利です。
[shell]SELECT gds_name,ctg_name,goods.ctg_id FROM goods INNER JOIN category b ON a.ctg_id b.ctg_id[/shell]
以上のようにテーブル名の後に半角スペースを空けて任意の文字列を記述することで、テーブルに列名をつけることができます。
最後に
今回は複数のテーブルから取得する方法の内部結合と、クロス結合について紹介いたしました。次回は、今回の続きとなる、外部結合について紹介致します。