リレーショナルデータベース — JOINと正規化
このトピックを終えると
テーブルを分割する理由を説明でき、JOINを使ってデータを結合するSQLを作成できるようになります。
1つのテーブルでは不十分
オンラインショッピングを作成するとしましょう。すべての注文情報を1つのテーブルに保存するとどうなるでしょうか?
text
orders (すべての情報を1つのテーブルに):
+----+--------+-------+----------+--------+
| id | 顧客名 | メール | 商品名 | 価格 |
+----+--------+-------+----------+--------+
| 1 | 김훈 | h@ex | ノートPC | 150万 |
| 2 | 김훈 | h@ex | マウス | 5万 |
| 3 | 이수 | s@ex | キーボード | 10万 |
+----+--------+-------+----------+--------+問題点はわかりますか?
- 重複: "김훈"と"h@ex"が注文するたびに繰り返されます。
- 修正のリスク: 김훈がメールアドレスを変更した場合、すべての行を修正する必要があります。1つでも見落とすと不整合が発生します。
- 削除のリスク: 김훈のすべての注文を削除すると、顧客情報自体が消えてしまいます。
テーブルの分割 — 正規化の基本
解決策は、関連するデータを別のテーブルに分割することです。
text
usersテーブル: ordersテーブル:
+----+--------+-------+ +----+---------+----------+--------+
| id | name | email | | id | user_id | product | price |
+----+--------+-------+ +----+---------+----------+--------+
| 1 | 김훈 | h@ex | | 1 | 1 | ノートPC | 150万 |
| 2 | 이수 | s@ex | | 2 | 1 | マウス | 5万 |
+----+--------+-------+ | 3 | 2 | キーボード | 10万 |
+----+---------+----------+--------+orders.user_idがusers.idを指します。これが外部キー(Foreign Key) — 2つのテーブルを接続するリンクです。
このように重複を削除し、テーブルを分割するプロセスを**正規化(Normalization)**と呼びます。
JOIN — 分割されたテーブルを結合する
テーブルを分割したので、再度結合して表示する方法が必要です。それがJOINです。
sql
-- 注文リストに顧客名を付加して照会
SELECT users.name, orders.product, orders.price
FROM orders
JOIN users ON orders.user_id = users.id;結果:
text
+--------+----------+--------+
| name | product | price |
+--------+----------+--------+
| 김훈 | ノートPC | 150万 |
| 김훈 | マウス | 5万 |
| 이수 | キーボード | 10万 |
+--------+----------+--------+JOIN ... ONの後に、どの列を基準にマッチングするかを指定します。orders.user_id = users.id — 注文のuser_idとユーザーのidが同じ行同士を結合します。
JOINの種類
sql
-- INNER JOIN: 両方にマッチする行のみ(デフォルト)
SELECT * FROM orders JOIN users ON orders.user_id = users.id;
-- LEFT JOIN: 左側のテーブルはすべて、右側はマッチするもののみ
-- 注文がない顧客も含む
SELECT users.name, orders.product
FROM users
LEFT JOIN orders ON users.id = orders.user_id;
-- 結果: 注文がない顧客はproductがNULLで表示される| JOINの種類 | 説明 |
|---|---|
INNER JOIN | 両方に存在するデータのみ |
LEFT JOIN | 左側すべて + 右側は存在すれば結合 |
RIGHT JOIN | 右側すべて + 左側は存在すれば結合 |
実務では、INNER JOINとLEFT JOINを最もよく使用します。
正規化 — なぜ分割するのか
正規化の基本的な原則は単純です: 1つの事実は1つの場所にのみ保存する。
| 正規化前 | 正規化後 | 効果 |
|---|---|---|
| 顧客名が注文ごとに繰り返される | usersテーブルに1回のみ | 重複の削除 |
| メールアドレスの変更時にN行修正 | 1行のみ修正 | 一貫性の保証 |
| 注文の削除時に顧客が消滅 | 顧客が独立して存在する | データの保存 |
正規化は「常に良い」わけではありません。テーブルが細かく分割されすぎると、JOINが複雑になり、パフォーマンスが低下する可能性があります。実務では、パフォーマンスのために意図的に重複を許可することもあります(非正規化)。しかし、基本は正規化です。