【SQLの基礎知識⑭】 表の指定(FROM句)と結合

SQLの基礎知識
SQLの基礎知識
この記事は約17分で読めます。

RDBでは1つの表でさまざなデータを表現しようとすると、表現しきれないデータがあったり、無駄な部分が増えたりするため、複数の表の結合により解決します。表の結合は、FROM句に複数の表を指定すると暗黙的に行われます。そこでまずはFROM句の記述について解説し、その後で表の結合について解説をしていきましょう。

Recommended Articles

表を指定するFROM句

SQL文では、表の指定をFROM句で行います。SQL文では表の指定が必要になるので、すでにここまでに何度も使ってきました。しかし、ここまで使ってこなかった指定として、複数の表の指定があります。複数の表を指定するには、FROM句に複数の表名を、「,」(カンマ)で区切って指定します。

書式 SELECT ...FROM <表名1>,<表名2>...
ところで、もしも2つの表を指定したとして、この2つに同じ名前の列があったらどうなるのでしょうか?例えば、つぎのような「表A」と「表B」の2つがあるとします。
表A
ナンバー名前
112ValueA1
123ValueA2
113ValueA3
126ValueA4
131ValueA5
表B
コード名前
112ValueB1
131ValueB2
ここで注目するのは、両方の表に「名前」列があることです。これら2つの表を指定して、「名前」列を表示させるSQL文を記述する「名前」列をどちらの表から取得して表示するかわからないため、エラーとなります。
SQL文 SELECT 名前 FROM 表A, 表B;
実行結果 エラーが発生しました。
この問題を解決するには、SELECT句の列を指定するところで、どの表から読み出すのか、次のように指定する必要があります。
書式 SELECT <表名>.<列名>, ... FROM <表名>,<表名>...

表名と列名を「.」(ピリオド)で接続して列を指定します。このように記述すると、たくさんの表を指定したSQL文であっても、読み出す列を一意に特定することができます。

SQL文 SELECT 表A.名前 FROM 表A,表B WHERE 表A.ナンバー = 表B.コード;
実行結果

名前
ValueA1
ValueA5
ここでは、WHERE句で「表A」の「ナンバー」列と「表B」の「コード」列の両方にあるものを、「表A」の「名前」列から読み出しています。このSQL文を見て気づくように、WHERE句の中でも表と列の両方を指定した書き方ができます。「<表名>.<列名>」の記述はどこでも使うことができます。
なお、2つの表に同じ名前の列がなければ、表名を指定しなくても問題なく動作します。しかし、表の列名はいつ追加されるかわからないので、SQL文を記述することきは「<表名>.<列名>」で記述しておくと、無用なトラブルを避けることができます。

別名による表の指定

表の指定には、別名を使うこともできます。これはここで解説した列の別名と同じです。表の名前が長いときや、わかりづらいときに、FROM句で表に別名を指定すると、その別名を列の選択や、WHERE句での指定に使うことができます。

【SQLの基礎知識⑩】 データ問合せの基本
この章では、SQLの基本中の基本と言っていいSELECT文について解説しています。また、重複した値をまとめるDISTINCTについても説明しています。いちれべ.comは、オラクル、MS-SQL、MS-Access で使用可能か一目でわかるサイトです。
書式
ORACLE MS-SQL
SELECT <別名>.<列名>, ・・・
FROM <表名1 別名1>,<表名1 別名2>, ・・・
MSAccess
SELECT <別名>.<列名>, ・・・
FROM
<表名1> AS <別名1>,<表名1> AS <別名2>, ・・・

列名の別名と同じように、ここでは記述しませんが、MSAccessでは「AS」が必要になります。それでは、先ほどのSQL文を、別名を使って記述してみます。
SQL文
SELECT A.名前 FROM 表A A, 表B B WHERE A.ナンバー=B.コード;
実行結果

名前
ValueA1
ValueA5
適切に別名をつけると、SQL文を簡潔にでき、プログラミングの効率が上がるので、有効に活用しよう。

表の結合について

実際の業務では、複数の表を使ってさまざまな処理を行っています。また、データ処理では、複数の表でさまざまな演算を行い、新たな表を作り出し、さらにその表を組合せてデータ処理を行うこともあります。

こうした、複数の表をつなぎ合わせる処理を結合(JOIN)といいます。結合には次のような種類があります。

  • 交差結合
  • 自然結合
    ①内部結合 ②外部結合

交差結合

2つの表を直積により結合することを交差結合またはクロス結合といいます。この結合は最も単純な結合です。

書式  MS-SQL
SELECT <列名1> ・・・ FROM <表1> CROSS JOIN <表2>
ORACLE MS-SQL MSAccess
SELECT <列名1> ・・・ FROM <表1> , <表2>

では実際に交差結合の例を見ていきましょう。次の2つの表を交差結合してみます。

表 : 名前リスト
社員番号勤務地コード
1001山田花子123
1022斉藤223
1056佐藤一郎223
表:事業所リスト
事業所コード事業所名
123品川事業所
223赤坂支社
301横浜営業所
SQL文
MS-SQL
SELECT * FROM 名前リスト CROSS JOIN 事業所リスト
ORACLE
 MS-SQL MSAccess
SELECT * FROM 名前リスト, 事業所リスト

実行結果

社員番号勤務地コード事業所コード事業所名
1001山田花子123123品川事業所
1022斉藤223123品川事業所
1056佐藤一郎223123品川事業所
1001山田花子123223赤坂支社
1022斉藤223223赤坂支社
1056佐藤一郎223223赤坂支社
1001山田花子123301横浜営業所
1022斉藤223301横浜営業所
1056佐藤一郎223301横浜営業所

この結果からわかるように、「名前リスト」表と「事業所リスト」表の行同士の組合せがすべて結果として返されています。列はそれぞれの表の列数を足した数に、行はそれぞれの表の行数を掛けた数になります。

自然結合 ①内部結合

自然結合とは、一方の表にある列の値と、もう一方の表のある列の値が同じ行を結び付ける結合です。このような結合を「等結合」と呼ぶこともあります。自然結合は「内部結合」と「外部結合」に分かれます。ここではまず内部結合から解説していきます。

内部結合(INNER JOIN)とは、一方の表の列の値ともう一方の表の列の値が同じ行だけを結合することを言います。内部結合は最もよく使う結合です。ORACLEでは、INNER JOINキーワード、ONキーワードに対応していないため、WHERE句の記述で内部結合を行います。他のRDBMS製品でも、INNER JOINキーワードやONキーワードを使わなくてもWHERE句の記述により内部結合を行うことができます。

書式  MS-SQL MSAccess
SELECT ・・・ FROM <表1> INNER JOIN <表2>
ON <表1>.<列1> = <表2>.<列2>
ORACLE MS-SQL MSAccess
SELECT ・・・ FROM <表1>, <表2>
WHERE <表1>.<列1> = <表2>.<列2>

この記述は、2つの表の間で対応する列を指定する記述です。それぞれで指定された列の値が同じ行が結果として返されます。

交差結合では全ての組合せが返されましたが、内部結合では、その中から条件により抽出されたもにとなります。この結合の条件を「結合条件」と呼びます。

記述自体はWHERE句に使われる通常の条件式と同じなのですが、条件が真になったときに動作が異なります。WHERE句に書かれた通常の条件式の場合には、条件が真になったばあには結果としてその行が返されます。子に対して結合条件が真になると、行に結合が行われます。

実際の使用例を見てみましょう。

表 : 顧客マスタ
顧客コード名前電話番号
110山田花子0312341234
112斉藤隆0451231234
115佐藤信也0354325432
120森葉子0434444444
122小泉加奈子0311221122
表:売上リスト
商品コード商品名販売価格販売日顧客コード
1100レンズなしカメラ110020010601112
1300透明なインク18020010601112
1100レンズなしカメラ120020010602115
1201角のない豆腐40020010602120
1301開かない蓋48020010603122

ここでは、「顧客マスタ」表の「顧客コード」列と「売上リスト」表の「顧客コード」列を内部結合するSQL文を記述してみます。

SQL文 MS-SQL MSAccess
SELECT 顧客マスタ.名前, 売上リスト.商品名, 売上リスト.販売価格
FROM 顧客マスタ INNER JOIN 売上リスト ON 顧客マスタ.顧客コード=売上リスト.顧客コード;
SQL文 ORACLE MS-SQL MSAccess
SELECT 顧客マスタ.名前, 売上リスト.商品名, 売上リスト.販売価格
FROM 顧客マスタ, 売上リスト WHERE 顧客マスタ.顧客コード=売上リスト.顧客コード;

実行結果

名前商品名販売価格
斉藤隆レンズなしカメラ1100
斉藤隆透明なインク180
佐藤信也レンズなしカメラ1200
森葉子角のない豆腐400
小泉加奈子開かない蓋480

「顧客マスタ」表の「顧客コード」列と「売上リスト」表の「顧客コード」列の値が同じ5行だけが結果として返されました。

また、さらに複数の表を結合することもできます。INNER JOIN句を使う場合には、INNER JOINを繰り返し記述していきます。1つ目の結合の記述を「( )」で囲み、最初に結合が行われるようにし、その結果に対してさらに内部結合するように記述します。WHERE句を使う場合には、FROM句に表名を追加し、WHERE句内に結合条件をすべてAND演算子でつないで記述します。

ここでは、「顧客マスタ」表と「売上リスト」表に、さらに次の「商品マスタ」表を結合してみます。

表:商品マスタ
商品コード商品名販売価格販売元
1100レンズなしカメラ1100びっくり愛
1300透明なインク180うつけ屋
1201角のない豆腐400裸の大様堂
1301開かない蓋480非実用INC
SQL文
MS-SQL MSAccess
SELECT 顧客マスタ.名前, 売上リスト.商品名, 商品マスタ.商品単価, 売上リスト.販売価格
FROM (顧客マスタ INNER JOIN 売上リスト ON 顧客マスタ.顧客コード=売上リスト.顧客コード)
INNER JOIN 商品マスタ ON 売上リスト.商品コード=商品マスタ.商品コード;
ORACLE MS-SQL MSAccess
SELECT 顧客マスタ.名前, 売上リスト.商品名, 商品マスタ.商品単価, 売上リスト.販売価格
FROM 顧客マスタ, 売上リスト, 商品マスタ
WHERE 顧客マスタ.顧客コード=売上リスト.顧客コード
AND 売上リスト.商品コード=商品マスタ.商品コード;

実行結果

名前商品名商品単価販売価格
斉藤隆レンズなしカメラ12001100
斉藤隆透明なインク180180
佐藤信也レンズなしカメラ12001200
森葉子角のない豆腐400400
小泉加奈子開かない蓋500480

なお、INNER JOINキーワードやONキーワードが使えるRDBMS製品を使っている場合には、WHERE句に結合条件を記述するよりも、これらのキーワードを使ったほうが良いでしょう。それは、表と表の結合関係がひと目でわかるだけでなく、通常の条件式との区別も容易になるからです。

また、一部のRDBMS製品では、INNER JOINキーワードの「INNER」を省略することもできます。そのため次のような記述も可能です。

SELECT 顧客マスタ.名前, 売上リスト.商品名, 商品マスタ.商品単価
FROM 顧客マスタ JOIN 売上リスト ON 顧客マスタ.顧客コード=売上リスト.顧客コード;

省略はすべての製品で可能な訳ではないので、マニュアルなどで仕様を確認してください。

内部結合と検索条件の指定

内部結合を行った結果に対して、さらに検索条件を設定することもできます。このとき結合は、WHERE句で検索条件の評価を行ううよりも先に実行されます。まずは結合し、その結合で作成された表に対して条件判断が行われることになります。

検索条件の指定はWHERE句に記述します。INNER JOINキーワードを使ていない場合はWHERE句にAND演算子を使って記述します。

SQL文
MS-SQL MSAccess
SELECT 顧客マスタ.名前, 売上リスト.商品名, 売上リスト.販売価格
FROM 顧客マスタ INNER JOIN 売上リスト ON 顧客マスタ.顧客コード=売上リスト.顧客コード
WHERE 売上リスト.販売日='20010602';
ORACLE MS-SQL MSAccess
SELECT 顧客マスタ.名前, 売上リスト.商品名, 売上リスト.販売価格
FROM 顧客マスタ, 売上リスト
WHERE 顧客マスタ.顧客コード=売上リスト.顧客コード AND 売上リスト.販売日='20010602';

実行結果

名前商品名販売価格
佐藤信也レンズなしカメラ1200
森葉子角のない豆腐400

先ほどの内部結合に抽出された5件から、さらに販売日により条件を絞り込んでいるので、2件だけが結果として返されました。

自然結合 ②外部結合

内部結合では、複数の表の間で対応する列の値が等しいものだけが結合され、結果として返されました。そのため、どちらかにしか存在しない値をもつ行は結合されませんでした。しかし、処理の目的によってはある表だけは必ず残したいという場合があります。こういった場合に用いるのが外部結合(OUTER JOIN)です。外部結合には、結合の方向により2つの種類があります。

  • 左外部結合
  • 右外部結合

なぜ、左や右という名前なのかというと、SQL文で先に記述した表名とSQL文で後に記述した表に指定した表のどちらを優先させるかを考えるからです。

左外部結合

左外部結合は、先に記述した左側の表を優先し、左側の表に関してはすべての行を残す結合です。

書式
MS-SQL MSAccess
SELECT ・・・ FROM <表1> LEFT OUTER JOIN <表2> ON <表1>.<列1> = <表2>.<列2>
ORACLE
SELECT ・・・ FROM <表1>, <表2> WHERE <表1>.<列1> = <表2>.<列2>(+)
MS-SQL
SELECT ・・・ FROM <表1>, <表2> WHERE <表1>.<列1> *= <表2>.<列2>

外部結合の書式にはたくさんの種類があります。

ORACLEではWHERE句の結合条件の中で、優先しない表の列名の後に「(+)」という記号を指定します。

MS-SQLでは LEFT OUTER JOIN キーワードによる記述の他に、WHERE句に記述された結合条件の記述に「*=」を使って指定することができます。

では、左外部結合で結合されなかった行はどのような扱いになるのでしょうか?結合されなかったからといって、返される結果にはそこに値がない訳ではありません。通常その部分にはNULLが格納されています。

SQL文
MS-SQL MSAccess
SELECT 顧客マスタ.名前, 売上リスト.商品名, 売上リスト.販売価格
FROM 顧客マスタ LEFT OUTER JOIN 売上リスト
ON 顧客マスタ.顧客コード=売上リスト.顧客コード;
ORACLE
SELECT 顧客マスタ.名前, 売上リスト.商品名, 売上リスト.販売価格
FROM 顧客マスタ, 売上リスト
WHERE 顧客マスタ.顧客コード=売上リスト.顧客コード(+);
MS-SQL
SELECT 顧客マスタ.名前, 売上リスト.商品名, 売上リスト.販売価格
FROM 顧客マスタ, 売上リスト
WHERE 顧客マスタ.顧客コード *= 売上リスト.顧客コード;

実行結果

名前商品名販売価格
山田花子  
斉藤隆レンズなしカメラ1100
斉藤隆透明なインク180
佐藤信也レンズなしカメラ1200
森葉子角のない豆腐400
小泉加奈子開かない蓋480
表:売上リスト
商品コード商品名販売価格販売日顧客コード
1100レンズなしカメラ110020010601112
1300透明なインク18020010601112
1100レンズなしカメラ120020010602115
1201角のない豆腐40020010602120
1301開かない蓋48020010603122
表 : 顧客マスタ
顧客コード名前電話番号
110山田花子0312341234
112斉藤隆0451231234
115佐藤信也0354325432
120森葉子0434444444
122小泉加奈子0311221122

結果を見るとわかるように、先に記述されている「顧客マスタ」表(左側)の行がすべて出力されています。そのため「山田花子」の行は商品名、販売価格の値としてNULLが入力されています。ORACLEではNULLを表示しないので、空白で出力されています。

右外部結合

右外部結合は、左外部結合とは反対に、後で指定した右側の表を優先し、右側の表に関してはすべての行を残す結合です。

書式
MS-SQL MSAccess
SELECT ・・・ FROM <表1> RIGHT OUTER JOIN <表2> ON <表1>.<列1> = <表2>.<列2>
ORACLE
SELECT ・・・ FROM <表1>, <表2> WHERE <表1>.<列1>(+) = <表2>.<列2>
MS-SQL
SELECT ・・・ FROM <表1>, <表2> WHERE <表1>.<列1> =* <表2>.<列2>

SQL文
MS-SQL  MSAccess
SELECT 顧客マスタ.名前, 売上リスト.商品名, 売上リスト.販売価格
FROM 顧客マスタ RIGHT OUTER JOIN 売上リスト
ON 顧客マスタ.顧客コード=売上リスト.顧客コード;
ORACLE
SELECT 顧客マスタ.名前, 売上リスト.商品名, 売上リスト.販売価格
FROM 顧客マスタ, 売上リスト
WHERE 顧客マスタ.顧客コード(+) = 売上リスト.顧客コード;
MS-SQL
SELECT 顧客マスタ.名前, 売上リスト.商品名, 売上リスト.販売価格
FROM 顧客マスタ, 売上リスト
WHERE 顧客マスタ.顧客コード =* 売上リスト.顧客コード;

実行結果

名前商品名販売価格
斉藤隆レンズなしカメラ1100
斉藤隆透明なインク180
佐藤信也レンズなしカメラ1200
森葉子角のない豆腐400
小泉加奈子開かない蓋480

この表では、名前が左側の表からの列になります。ここではNULLになっている行はありません。なぜなら「売上リスト」表が右側になっているため、この表の中に顧客名が入っていないことはないためです。

関連リンク

次の章へ進む
【SQLの基礎知識⑮】 副問い合わせ(サブクエリ)
SQL文の中にさらにSQL文を追加して記述することを副問合せやサブクエリと呼びます。ここではSQLにおける副問合せついて解説します。いちれべ.comは、オラクル、MS-SQL、MS-Access で使用可能か一目でわかるサイトです。
目次
【SQLの基礎知識】基本ルールや基礎の基礎をマスターしよう
こちらの記事を読み進めることで、SQLの基礎が充分に身に付きます。これからSQLを身に着けたい初心者・入門者の方に最適です。データベース製品ごとに表現方法が異なることがありますので、ある程度SQLのスキルがある方も利用できるサイトです。
Recommended Articles