はじめに
複数テーブルの結合を学ぶ。動作確認のため次の2つのテーブル TEST1, TEST2を準備する。TEST1 は STATUS の簡易版、TEST2 は後に追加するテーブル AFF の簡易版である。
NAME | LEVEL |
---|---|
御坂美琴 | 5 |
上条当麻 | 0 |
白井黒子 | 4 |
NAME | TEAM |
---|---|
御坂美琴 | 常盤台中 |
白井黒子 | 常盤台中 |
白井黒子 | ジャッジメント |
神裂火織 | 天草式十字凄教 |
この2つのテーブルを作成するために、次のコマンドを入力(コピペ)する。
CREATE TABLE TEST1 ( NAME TEXT PRIMARY KEY, LEVEL INTEGER, CHECK( 0 <= LEVEL ), CHECK( 5 >= LEVEL ) ) ; INSERT INTO TEST1 VALUES ( '御坂美琴', 5 ) ; INSERT INTO TEST1 VALUES ( '上条当麻', 0 ) ; INSERT INTO TEST1 VALUES ( '白井黒子', 4 ) ; CREATE TABLE TEST2 ( NAME TEXT, TEAM TEXT, PRIMARY KEY ( NAME, TEAM ), FOREIGN KEY ( NAME ) REFERENCES STATUS ) ; INSERT INTO TEST2 VALUES ( '御坂美琴', '常盤台中' ) ; INSERT INTO TEST2 VALUES ( '白井黒子', '常盤台中' ) ; INSERT INTO TEST2 VALUES ( '白井黒子', 'ジャッジメント' ) ; INSERT INTO TEST2 VALUES ( '神裂火織', '天草式十字凄教' ) ;
直積
テーブル名に2つのテーブルを並べただけであるが、SELECT * FROM TEST1, TEST2 ; と入力してみよう。結果は次のようになる。
NAME | LEVEL | NAME | TEAM |
---|---|---|---|
御坂美琴 | 5 | 御坂美琴 | 常盤台中 |
御坂美琴 | 5 | 白井黒子 | 常盤台中 |
御坂美琴 | 5 | 白井黒子 | ジャッジメント |
御坂美琴 | 5 | 神裂火織 | 天草式十字凄教 |
上条当麻 | 0 | 御坂美琴 | 常盤台中 |
上条当麻 | 0 | 白井黒子 | 常盤台中 |
上条当麻 | 0 | 白井黒子 | ジャッジメント |
上条当麻 | 0 | 神裂火織 | 天草式十字凄教 |
白井黒子 | 4 | 御坂美琴 | 常盤台中 |
白井黒子 | 4 | 白井黒子 | 常盤台中 |
白井黒子 | 4 | 白井黒子 | ジャッジメント |
白井黒子 | 4 | 神裂火織 | 天草式十字凄教 |
TEST1 が3データ、TEST2 が4データあり、それらを単純に組み合わせた12データが表示された。このテーブルを TEST1 と TEST2 の直積または交差結合と言う。2列に現れている NAME の値が異なり、2つのデータの関連性が考慮されていない。このままでは利用価値は低そうで、意味のある行だけを抜き出す必要がある。
内部結合
2つのテーブルは属性 NAME を共有することで関連している。テーブルの関連付けのために WHERE 句を使った問い合わせ文を試してみる。これを旧形式の結合と言う。
SELECT * FROM TEST1, TEST2 WHERE TEST1.NAME = TEST2.NAME ;
WHERE 句内で NAME の指定はどちらのテーブルを意味するか分からないので、TEST1.NAME, TEST2.NAME のように指定する。
NAME | LEVEL | NAME | TEAM |
---|---|---|---|
御坂美琴 | 5 | 御坂美琴 | 常盤台中 |
白井黒子 | 4 | 白井黒子 | 常盤台中 |
白井黒子 | 4 | 白井黒子 | ジャッジメント |
NAME が2つあるが、左が TEST1, 右が TEST2 に対応していると解するのが自然だろう。結果の特徴をまとめる。
- 共通する属性が重複する。次のように使えば、特に支障はないだろう。
SELECT TEST1.NAME, LEVEL, TEAM FROM TEST1, TEST2 WHERE TEST1.NAME = TEST2.NAME ; - TEST1 にあった「上条当麻」のデータは、対応するデータが TEST2 に無いので失われる。
- TEST2 にあった「神裂火織」のデータは、対応するデータが TEST1 に無いので失われる。
これらは特徴であって、利用目的次第では問題はない。下の2つの性質が内部結合の特徴である。
NAME の重複が気になるのであれば、自然結合という方法がある。
SELECT * FROM TEST1 NATURAL JOIN TEST2 ;
NAME | LEVEL | TEAM |
---|---|---|
御坂美琴 | 5 | 常盤台中 |
白井黒子 | 4 | 常盤台中 |
白井黒子 | 4 | ジャッジメント |
共通する属性を検出してまとめられているが、勝手に属性を判断されるのは危険かもしれない。結果的には旧形式と同じになるが、WHERE 句を使わない表現として内部結合がある。
SELECT * FROM TEST1 INNER JOIN TEST2 ON TEST1.NAME = TEST2.NAME ;
WHERE 句の代わりに ON で表現されただけに見えるが、長くなりがちな WHERE 句が簡潔になる利点はあるだろう。旧形式は内部結合の1つの表現と考えられる。
外部結合
内結合では相手に対応するデータがなければ、データは捨てられていた。対応するデータがない場合に相手を NULL にして保存するのが外部結合である。左側のテーブルを保存する場合を左外部結合、右側を保存する場合を右外部結合、両方残す場合を完全外部結合という。
- 左外部結合
SELECT * FROM TEST1 LEFT OUTER JOIN TEST2 ON TEST1.NAME = TEST2.NAME ; - 右外部結合
SELECT * FROM TEST1 RIGHT OUTER JOIN TEST2 ON TEST1.NAME = TEST2.NAME ; - 完全外部結合
SELECT * FROM TEST1 FULL OUTER JOIN TEST2 ON TEST1.NAME = TEST2.NAME ;
完全害結合は MySQL では使えないとか、ソフトウェアによって利用できないものがあるらしい。各外部結合の結果を提示する。対応するデータがない場合は空欄になっていることが分かる。空欄は NULL として扱われる。
NAME | LEVEL | NAME | TEAM |
---|---|---|---|
御坂美琴 | 5 | 御坂美琴 | 常盤台中 |
上条当麻 | 0 | ||
白井黒子 | 4 | 白井黒子 | ジャッジメント |
白井黒子 | 4 | 白井黒子 | 常盤台中 |
NAME | LEVEL | NAME | TEAM |
---|---|---|---|
御坂美琴 | 5 | 御坂美琴 | 常盤台中 |
白井黒子 | 4 | 白井黒子 | ジャッジメント |
白井黒子 | 4 | 白井黒子 | 常盤台中 |
神裂火織 | 天草式十字凄教 |
NAME | LEVEL | NAME | TEAM |
---|---|---|---|
御坂美琴 | 5 | 御坂美琴 | 常盤台中 |
上条当麻 | 0 | ||
白井黒子 | 4 | 白井黒子 | ジャッジメント |
白井黒子 | 4 | 白井黒子 | 常盤台中 |
神裂火織 | 天草式十字凄教 |