CodeGym /课程 /SQL SELF /使用 ON DELETE CASCADEON UPDATE RES...

使用 ON DELETE CASCADEON UPDATE RESTRICT

SQL SELF
第 19 级 , 课程 2
可用

想象一下,你建了一个数据库,有一个客户表(customers)和跟客户相关的订单表(orders)。但有时候会遇到这样的问题:如果某个客户从 customers 表里被删了怎么办?这个客户的订单也要一起删掉,还是让它们变成“孤儿”,指向一个不存在的客户?还有,如果你想改客户的 ID 呢?这时候就轮到级联操作(CASCADE)和限制(RESTRICT)来帮你控制数据库的行为了。

ON DELETE CASCADE —— 这个机制会在你从父表删掉一条记录时,自动把所有相关的子表记录也删掉。换句话说,如果你删了一个客户,所有和他有关的订单也会被删掉。

它的工作方式是这样的。当你在外键定义里加上 ON DELETE CASCADE,数据库就“明白”了,相关的记录也要自动删掉。

例子

假设我们有两张表:customersorders。一个客户 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,如果子表有记录引用这个主键,数据库就不让你改父表的键。

例子

我们还是用 customersorders 这两张表,不过这次在外键上加上了更新限制。

-- 重新创建订单表,加上更新限制
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".

你看,数据库直接报错了,因为更改主键会破坏表之间的关联。

关于 UPDATE 和它的细节,下一级我会再详细讲 :P

结合 ON DELETE CASCADEON 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,会报错。

为什么在实际项目中很重要?

CASCADERESTRICT 对于有很多关联表的大型系统来说非常重要。比如:

在电商网站里,一个客户可以有订单。如果客户决定删除自己的账号,你肯定不想让数据库里留下那些已经没有任何关联的订单。这时候 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