Hãy tưởng tượng bạn vừa tạo một database, trong đó có bảng khách hàng (customers) và các đơn hàng liên quan (orders). Nhưng rồi sẽ có lúc bạn phải xử lý tình huống: nếu một khách hàng bị xoá khỏi bảng customers thì sao? Các đơn hàng của khách đó cũng nên bị xoá luôn, hay để lại "mồ côi", trỏ tới một khách không còn tồn tại? Và nếu bạn muốn đổi ID của khách thì sao? Đây chính là lúc các thao tác cascade (CASCADE) và hạn chế (RESTRICT) xuất hiện để giúp bạn kiểm soát hành vi của database.
ON DELETE CASCADE là một cơ chế tự động xoá các bản ghi liên quan khi bạn xoá một bản ghi ở bảng cha. Nói cách khác, nếu bạn xoá một khách hàng, thì tất cả đơn hàng liên quan cũng sẽ bị xoá theo.
Nó hoạt động như này: Khi bạn thêm ON DELETE CASCADE vào định nghĩa khoá ngoại, database sẽ "hiểu" rằng bản ghi liên quan cần được tự động xoá luôn.
Ví dụ
Giả sử mình có hai bảng: customers và orders. Khách hàng customers có thể có nhiều đơn hàng orders, tương ứng với quan hệ ONE-TO-MANY. Mục tiêu là khi xoá khách hàng thì tất cả đơn hàng của họ cũng bị xoá.
-- Tạo bảng khách hàng
CREATE TABLE customers (
customer_id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
-- Tạo bảng đơn hàng với khoá ngoại trỏ tới bảng khách hàng
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_id INT REFERENCES customers(customer_id) ON DELETE CASCADE,
order_date DATE NOT NULL
);
Chèn dữ liệu vào các bảng
-- Chèn dữ liệu vào bảng khách hàng
INSERT INTO customers (name) VALUES ('Ivan'), ('Anna');
-- Chèn dữ liệu vào bảng đơn hàng
INSERT INTO orders (customer_id, order_date) VALUES
(1, '2023-10-01'),
(1, '2023-10-02'),
(2, '2023-10-03');
Bảng orders:
| order_id | customer_id | order_date |
|---|---|---|
| 1 | 1 | 2023-10-01 |
| 2 | 1 | 2023-10-02 |
| 3 | 2 | 2023-10-03 |
Xoá khách hàng và kiểm tra kết quả
-- Xoá khách hàng có ID 1
DELETE FROM customers WHERE customer_id = 1;
-- Kiểm tra còn gì trong bảng đơn hàng
SELECT * FROM orders;
| order_id | customer_id | order_date |
|---|---|---|
| 3 | 2 | 2023-10-03 |
Như bạn thấy, các đơn hàng liên quan tới khách đã bị xoá cũng bị xoá luôn.
Hạn chế thay đổi: ON UPDATE RESTRICT
ON UPDATE RESTRICT giúp ngăn không cho thay đổi giá trị ở bảng cha nếu có bản ghi ở bảng con đang tham chiếu tới giá trị đó. Nó giống như một "hàng rào bảo vệ", ngăn các thay đổi có thể phá vỡ tính toàn vẹn dữ liệu.
Nó hoạt động như này: Khi bạn thêm ON UPDATE RESTRICT, database sẽ không cho phép cập nhật khoá ở bảng cha nếu có bản ghi ở bảng con đang tham chiếu tới khoá đó.
Ví dụ
Mình vẫn dùng hai bảng customers và orders, nhưng sẽ thêm hạn chế cập nhật vào khoá ngoại.
-- Tạo lại bảng đơn hàng với hạn chế cập nhật
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
);
Thử cập nhật ID khách hàng
-- Thử đổi ID khách hàng từ 2 thành 5
UPDATE customers
SET customer_id = 5
WHERE customer_id = 2;
Kết quả:
ERROR: update or delete on table "customers" violates foreign key constraint
DETAIL: Key (customer_id)=(2) is still referenced from table "orders".
Như bạn thấy, database báo lỗi vì việc đổi khoá sẽ phá vỡ liên kết giữa các bảng.
Mình sẽ nói kỹ hơn về UPDATE và các chi tiết của nó ở level sau nha :P
Kết hợp ON DELETE CASCADE và ON UPDATE RESTRICT
Dĩ nhiên, bạn có thể kết hợp cascade (CASCADE) và hạn chế (RESTRICT). Ví dụ, bạn có thể tự động xoá dữ liệu liên quan khi xoá bản ghi cha (ON DELETE CASCADE), nhưng lại cấm thay đổi ID của nó (ON UPDATE RESTRICT) để tránh hậu quả không mong muốn.
Ví dụ
Tạo lại bảng đơn hàng, dùng cả hai cơ chế:
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
);
Bây giờ:
- Nếu bạn xoá khách hàng, tất cả đơn hàng của họ cũng bị xoá.
- Nếu bạn thử đổi ID khách hàng, sẽ bị báo lỗi.
Tại sao nó quan trọng trong dự án thực tế?
Sử dụng CASCADE và RESTRICT cực kỳ quan trọng với các hệ thống lớn có nhiều bảng liên quan. Ví dụ:
Trong một shop online, khách hàng có thể có các đơn hàng. Nếu khách quyết định xoá profile, bạn không muốn để lại các đơn hàng không còn liên kết gì. Lúc này ON DELETE CASCADE sẽ giúp bạn.
Đồng thời, bạn cũng muốn ngăn việc vô tình đổi khoá duy nhất, để không phá vỡ liên kết giữa các bảng. Đó là lúc ON UPDATE RESTRICT phát huy tác dụng.
GO TO FULL VERSION