CodeGym /コース /SQL SELF /ON DELETE CASCADE と ON UPDATE RESTRIC...

ON DELETE CASCADE と ON UPDATE RESTRICT の使い方

SQL SELF
レベル 19, レッスン 2
使用可能

例えば、君がデータベースを作って、そこに顧客テーブル(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 が便利だよ。

2
タスク
SQL SELF, レベル 19, レッスン 2
ロック未解除
ON DELETE CASCADE付きテーブルの作成
ON DELETE CASCADE付きテーブルの作成
2
タスク
SQL SELF, レベル 19, レッスン 2
ロック未解除
ON UPDATE RESTRICT 制約の追加
ON UPDATE RESTRICT 制約の追加
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION