例えば、君がデータベースを作って、そこに顧客テーブル(customers)と、その顧客に紐づく注文(orders)のテーブルがあるとしよう。でも、ある時「もし顧客がcustomersテーブルから消されたらどうなる?」って問題が出てくるよね。その顧客の注文も消すべき?それとも「孤児」状態で存在し続ける?さらに、顧客のIDを変更したい時は?ここで登場するのが、カスケード操作(CASCADE)と制約(RESTRICT)で、データベースの振る舞いをコントロールできるんだ。
ON DELETE CASCADE は、親テーブルのレコードを削除した時に、関連する子テーブルのレコードも自動で削除してくれる仕組み。つまり、顧客を消したら、その顧客の注文も全部消えるってこと。
仕組みはこんな感じ。外部キー定義に ON DELETE CASCADE を追加すると、DBが「関連レコードも自動で消すんだな」って理解してくれる。
例
例えば、customers と orders の2つのテーブルがあるとしよう。customers(顧客)は複数のorders(注文)を持てる、つまり ONE-TO-MANY の関係だ。顧客を消したら、その人の注文も全部消したいよね。
-- 顧客テーブルを作成
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) ON DELETE CASCADE,
order_date DATE NOT NULL
);
テーブルにデータを挿入しよう
-- 顧客テーブルにデータを挿入
INSERT INTO customers (name) VALUES ('イワン'), ('アンナ');
-- 注文テーブルにデータを挿入
INSERT INTO orders (customer_id, order_date) VALUES
(1, '2023-10-01'),
(1, '2023-10-02'),
(2, '2023-10-03');
ordersテーブル:
| order_id | customer_id | order_date |
|---|---|---|
| 1 | 1 | 2023-10-01 |
| 2 | 1 | 2023-10-02 |
| 3 | 2 | 2023-10-03 |
顧客を削除してどうなるか見てみよう
-- IDが1の顧客を削除
DELETE FROM customers WHERE customer_id = 1;
-- 注文テーブルに何が残ってるか確認
SELECT * FROM orders;
| order_id | customer_id | order_date |
|---|---|---|
| 3 | 2 | 2023-10-03 |
見ての通り、削除された顧客に紐づく注文も一緒に消えたね。
変更の制限:ON UPDATE RESTRICT
ON UPDATE RESTRICT は、親テーブルの値が子テーブルで参照されている場合、その値の変更を防いでくれる。つまり「ガードレール」みたいなもので、データの整合性を壊すような変更をブロックしてくれるんだ。
どう動くかというと、ON UPDATE RESTRICT を追加すると、親テーブルのキーを子テーブルが参照している限り、そのキーの更新はできなくなる。
例
さっきの customers と orders テーブルを使うけど、今度は外部キーに更新制限をつけてみる。
-- 注文テーブルを更新制限付きで作り直す
DROP TABLE orders;
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_id INT REFERENCES customers(customer_id) ON UPDATE RESTRICT,
order_date DATE NOT NULL
);
顧客IDを更新してみよう
-- 顧客IDを2から5に変更しようとする
UPDATE customers
SET customer_id = 5
WHERE customer_id = 2;
結果:
ERROR: update or delete on table "customers" violates foreign key constraint
DETAIL: Key (customer_id)=(2) is still referenced from table "orders".
見ての通り、DBがエラーを返してくる。キーの変更がテーブル間の関係を壊すからだね。
UPDATE の詳細やコツは次のレベルで話すよ :P
ON DELETE CASCADE と ON UPDATE RESTRICT の組み合わせ
もちろん、カスケード操作(CASCADE)と制約(RESTRICT)は組み合わせて使える。例えば、親レコード削除時に関連データを自動削除(ON DELETE CASCADE)しつつ、IDの変更は禁止(ON UPDATE RESTRICT)みたいな設定もできるよ。
例
もう一度注文テーブルを両方の仕組みで作ってみよう:
DROP TABLE orders;
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_id INT REFERENCES customers(customer_id)
ON DELETE CASCADE
ON UPDATE RESTRICT,
order_date DATE NOT NULL
);
これで:
- 顧客を削除したら、その人の注文も全部消える。
- 顧客IDを変更しようとしたらエラーになる。
実際のプロジェクトでなぜ大事なの?
CASCADE や RESTRICT の使い方は、たくさんのテーブルが絡む大規模システムで超重要。例えば:
ネットショップなら、顧客が注文を持ってる。もし顧客が自分のアカウントを消したら、もう参照されない注文をDBに残したくないよね。ここで ON DELETE CASCADE が役立つ。
逆に、ユニークキーをうっかり変更してテーブル間の関係を壊したくない時は ON UPDATE RESTRICT が便利だよ。
GO TO FULL VERSION