リレーショナルDBの仕組み
顧客が引っ越すたびに、注文を 200 行書き換える
注文を 1 枚の表で管理していたとします。1 行の中に、注文の情報と一緒に顧客の氏名・住所・電話番号まで並べる作り方です。最初は分かりやすいのですが、常連客が 1 人引っ越しただけで、その人の注文 200 行すべての住所を書き換えることになります。1 行でも直し忘れれば、同じ顧客に住所が 2 つ存在する表ができあがります。
原因は、顧客という 1 件の事実を、注文の数だけ複製して持っていることです。リレーショナルデータベースは、ここを分けます。顧客は customers に 1 人 1 行、注文は orders に 1 件 1 行。住所は customers にしか無いので、引っ越しの修正は 1 行で終わります。
分けると面倒が増えそうに見えますが、実際には逆です。まだ 1 度も注文していない顧客を登録できますし、注文が何件に増えても顧客側は 1 行のままです。1 枚の表に混ぜている限り、注文の無い顧客は行そのものを作れません。
表と表は、id を書いた列でつなぐ
分けた表は、片方に相手の id を書いた列を持たせてつなぎます。
SQL クエリ
CREATE TABLE orders (
id INT PRIMARY KEY,
customer_id INT NOT NULL,
total INT NOT NULL,
FOREIGN KEY (customer_id) REFERENCES customers (id)
);customer_id のように、別の表の主キーを指す列を外部キーと呼びます。ここが「リレーショナル (関係) 」という名前の中身です。表そのものが関係を持っているのではなく、この 1 列が関係の実体です。
外部キーを宣言しておくと、customers に存在しない id を orders に入れようとした時点で拒否されます。アプリのバグでも、手で流した修正 SQL でも、他部署が動かしたバッチでも同じように弾かれます。書き込む経路がどこであっても守られる、という点がアプリ側のチェックとの決定的な違いです。
表計算ソフトと違う 3 つの約束
同じ「表」に見えても、守っている約束が違います。
- 行に順序はありません。 上から 3 番目の行、という指定はできません。ほしい順に並べるのは取り出す側の仕事です
- 列には型と制約があります。 数値として定義した列に文字は入りません
- 表どうしは id でつながります。 同じ値を 2 か所に書き写しません
この 3 つを守る代わりに、表計算ソフトのような自由さは手放します。手放した自由の分だけ、データの意味が壊れにくくなります。
演習では customers から必要な列を取り出します。顧客の情報が 1 人 1 行にまとまっていて、住所がどこにも重複していないことを確かめてください。
テーブル構造
CREATE TABLE customers (
id INT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
city VARCHAR(30) NOT NULL
);
CREATE TABLE orders (
id INT PRIMARY KEY,
customer_id INT NOT NULL,
amount INT NOT NULL,
ordered_on DATE NOT NULL
);
INSERT INTO customers (id, name, city) VALUES
(1, '田中', '東京'),
(2, '鈴木', '大阪'),
(3, '佐藤', '名古屋'),
(4, '高橋', '札幌');
INSERT INTO orders (id, customer_id, amount, ordered_on) VALUES
(101, 1, 1200, '2026-04-01'),
(102, 1, 3400, '2026-04-15'),
(103, 2, 2200, '2026-04-20'),
(104, 3, 5000, '2026-05-01');期待される出力
| id | name | city |
|---|---|---|
| 1 | 田中 | 東京 |
| 2 | 鈴木 | 大阪 |
| 3 | 佐藤 | 名古屋 |
| 4 | 高橋 | 札幌 |