例えば、学生のデータが入ったテーブルと、コースのデータが入ったテーブルがあるとするよ。どの学生がどのコースを受講してるかって、どうやって表現する?学生テーブルに受講してるコース全部を入れるカラムを追加するって手もあるけど、それだとすぐにカオスになるよね。そこで一番いい方法のひとつが、外部キーを使うこと!
外部キー(FOREIGN KEY)っていうのは、テーブル同士のつながりを作るためのカラム(またはカラムのセット)なんだ。他のテーブルのカラム(たいていはPRIMARY KEY)を指してて、データの参照整合性を保証してくれる。だから、もし誰かの学生がコースを受講してるってなったら、そのコースが本当に存在してるってことがちゃんと保証されるんだ。
外部キーのメリット:
- データの整合性を保ってくれる。つまり、あるテーブルのレコードが他のテーブルのデータとちゃんと対応してることを保証してくれる。
- データベースが分かりやすくて論理的に整理される。
- データ処理が楽になるし、重複やミスも防げる。
リアルな例
図書館をイメージしてみて。booksテーブルには本のリスト、membersテーブルには読者のリストがある。誰がどの本を借りたかを管理するには、borrowed_booksテーブルを作って、そこからbooksとmembersに外部キーでつなげるんだ。こうすれば、誰がどの本を借りたか一発で分かる!
テーブル間のリレーションの種類
外部キーを使うと、いろんなテーブル同士の関係を表現できる。ここで代表的な3つのタイプを見てみよう:
1. 「1対1」リレーション(ONE-TO-ONE)
一番シンプルな関係で、あるテーブルの1レコードが、別のテーブルの1レコードとだけ対応してるパターン。例えば、usersテーブルにユーザー情報があって、profilesテーブルに追加情報(住所や写真とか)がある場合とか。
ONE-TO-ONEリレーションのSQL例:
CREATE TABLE users (
user_id SERIAL PRIMARY KEY,
username TEXT NOT NULL
);
CREATE TABLE profiles (
profile_id SERIAL PRIMARY KEY,
user_id INT UNIQUE REFERENCES users(user_id), -- users.user_idを参照
address TEXT
);
ここではprofilesテーブルのuser_idカラムが外部キーになってて、usersテーブルのuser_idを参照してるよ。
usersテーブルの例:
| user_id - PRIMARY KEY | username |
|---|---|
| 1 | alice |
| 2 | bob |
| 3 | charlie |
profilesテーブルの例:
| profile_id - PRIMARY KEY | user_id - FOREIGN KEY | address |
|---|---|---|
| 1 | 1 | Berlin, Germany |
| 2 | 2 | Paris, France |
| 3 | 3 | Tokyo, Japan |
2. 「1対多」リレーション(ONE-TO-MANY)
これが一番よく使われる関係。例えば、1人の顧客がたくさんの注文をする場合。customersテーブルとordersテーブルを外部キーでつなげる感じ。
ONE-TO-MANYリレーションのSQL例:
CREATE TABLE customers (
customer_id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_id INT REFERENCES customers(customer_id), -- customers.customer_idを参照
order_date DATE NOT NULL
);
ordersテーブルには、同じcustomersテーブルの1レコードを指す複数のレコードが入ることができるよ。
customersテーブルの例:
| customer_id - PRIMARY KEY | name |
|---|---|
| 1 | Alice |
| 2 | Bob |
| 3 | Charlie |
ordersテーブルの例:
| order_id - PRIMARY KEY | customer_id - FOREIGN KEY | order_date |
|---|---|---|
| 1 | 1 | 2024-12-01 |
| 2 | 1 | 2024-12-05 |
| 3 | 2 | 2024-12-03 |
| 4 | 3 | 2024-12-07 |
3. 「多対多」リレーション(MANY-TO-MANY)
たまに、あるテーブルの1レコードが別のテーブルの複数レコードとつながってて、逆もまた然りってパターンがある。例えば、学生がいろんなコースを受講できて、1つのコースにもたくさんの学生がいる場合。こういう時は中間テーブルを作るのが定番。
MANY-TO-MANYリレーションのSQL例:
-- 学生
CREATE TABLE students (
student_id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
-- コース
CREATE TABLE courses (
course_id SERIAL PRIMARY KEY,
title TEXT NOT NULL
);
-- "特定の学生が特定のコースを受講してる"
CREATE TABLE enrollments (
student_id INT REFERENCES students(student_id), -- 学生IDへの参照
course_id INT REFERENCES courses(course_id), -- コースIDへの参照
PRIMARY KEY (student_id, course_id)
);
ここではenrollmentsテーブルがstudentsとcoursesの「橋渡し」役になってるよ。
studentsテーブルの例:
| student_id - PRIMARY KEY | name |
|---|---|
| 1 | Alice |
| 2 | Bob |
| 3 | Charlie |
coursesテーブルの例:
| course_id - PRIMARY KEY | title |
|---|---|
| 1 | SQL Basics |
| 2 | Data Structures |
| 3 | Algorithms |
enrollmentsテーブルの例:
| student_id - FOREIGN KEY | course_id - FOREIGN KEY |
|---|---|
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
| 3 | 3 |
外部キーを使うメリット
- データが一貫性を保てる。 外部キーが存在しないレコードを指してたら、PostgreSQLはINSERTやUPDATEを許してくれない。
- テーブル操作が楽になる。 外部キーがあると、テーブル間のデータを簡単につなげて、
JOINみたいな複雑なクエリも書きやすい。 - 自動的な動作。 関連レコードを削除・更新した時の動作(カスケード削除、
NULLセットなど)も設定できる。
PostgreSQLでの外部キーの書き方は?
テーブル作成時に外部キーを追加する基本の書き方:
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_id INT REFERENCES customers(customer_id) -- 外部キー参照
);
ここで:
customer_id— これが外部キー。- これは
customersテーブルのcustomer_idを参照してる。
FOREIGN KEYを明示的に書くこともできるよ:
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_id INT,
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);
豆知識
「外部キー(FOREIGN KEY)」って言葉は、1970年代にエドガー・コッドが考えたリレーショナルデータベース理論から来てるんだ。びっくりだけど、このアイデアは今でも現役で、モダンなデータベースの超重要な要素なんだよ。クラシックってやっぱりすごい!
これで外部キーが何か、なんで大事なのか分かったよね。テーブル作成時の外部キーの作り方や、カスケード操作の使い方はまた次のレクチャーで!
GO TO FULL VERSION