五种主流数据库:增删改合

除查询语句外,SQL 还提供了对数据进行插入、更新、删除以及合并的数据操作语言(DML)。

本文比较了五种主流数据库实现的数据增删改合功能,包括 MySQL、Oracle、SQL Server、PostgreSQL 以及 SQLite。

插入数据

SQL 标准主要提供了两种插入数据的语法:

  • INSERT INTO … VALUES …

  • INSERT INTO … SELECT …

第一种语法用于将指定的数据插入目标表,第二种语法可以将一个查询结果插入目标表。

插入单行记录

第一种插入语法的基本格式如下:

INSERT INTO t(col1, col2, ...)
VALUES (value1, value2, ...);

其中 t 是插入数据的目标表,VALUES 子句提供了需要插入的数据,valueN 的数量必须和 INSERT INTO 子句中的字段 colN 数量相同,并且数据类型能够兼容。例如:

INSERT INTO employee (emp_name, sex, dept_id, manager, hire_date,
job_id, salary, bonus, email, comments,
create_by, create_ts, update_by, update_ts)
VALUES ('张三', '男', 5, 18, CURRENT_DATE, -- Microsoft SQL Server 需要替换该函数
10, 6000, NULL, 'zhangsan@shuguo.com', NULL,
'Admin', CURRENT_TIMESTAMP, NULL, NULL);

-- Oracle 需要执行以下COMMIT 语句
-- COMMIT;

以上语句的作用是增加一名新员工。其中 CURRENT_DATE 和 CURRENT_TIMESTAMP 函数分别返回了系统的当前日期和时间戳。另外,员工表中的 emp_id 是一个自增字段,无须我们提供数据,由数据库系统自动生成。

如果使用 Microsoft SQL Server,我们需要使用 CAST(GETDATE() AS DATE)函数返回系统的当前日期。

如果使用 Oracle 数据库,我们需要在执行 INSERT 语句之后使用 COMMIT 语句提交修改,包括本章后续的所有示例。具体原因我们将会在后续文章中进行解释。

以上语句执行成功之后,我们可以查看最新插入的数据:

SELECT emp_id, emp_name, sex
FROM employee
WHERE emp_name = '张三';

emp_id|emp_name|sex
------|--------|---
26| 张三 |

如果我们再次执行上面的插入语句,将会产生以下错误:

-- Oracle
SQL 错误 [1] [23000]: ORA-00001: 违反唯一约束条件 (TONY.UK_EMP_EMAIL)

-- MySQL
SQL 错 误 [1062] [23000]: Duplicate entry 'zhangsan@shuguo.com' for key
'employee.uk_emp_email'

-- Microsoft SQL Server
SQL 错误 [2627] [23000]: 违反了 UNIQUE KEY 约束“uk_emp_email ”。不能在对象
“dbo.employee”中插入重复键。重复键值为 (zhangsan@shuguo.com)

-- PostgreSQL
SQL 错误 [23505]: 错误: 重复键违反唯一约束"uk_emp_email"
详细:键值"(email)=(zhangsan@shuguo.com)" 已经存在

-- SQLite
SQL 错误 [19]: [SQLITE_CONSTRAINT] Abort due to constraint violation (UNIQUE
constraint failed: employee.email)

数据库在插入、更新或者删除数据之前会执行数据的完整性检查。如果违反约束,将会返回错误信息,而不会修改数据。以上语句违反了 email 字段上的唯一约束,下面两个语句则分别违反了非空约束和检查约束:

-- 违反非空约束,sex 字段不能为空
INSERT INTO employee (emp_name)
VALUES('张三');

-- 违反检查约束,salary 必须大于0
INSERT INTO employee (emp_name, sex, dept_id, manager, hire_date,
job_id, salary, bonus, email, comments,
create_by, create_ts, update_by, update_ts)
VALUES ('李四', '女', 5, 18, CURRENT_DATE, -- Microsoft SQL Server 需要替换该函数
10, 0, NULL, 'lisi@shuguo.com', NULL,
'Admin', CURRENT_TIMESTAMP, NULL, NULL);

如果我们在定义表的字段时指定了默认值,也可以使用 DEFAULT 插入默认值,例如:

CREATE TABLE t_default(
id INTEGER,
c INTEGER DEFAULT 100
);

INSERT INTO t_default VALUES (1, DEFAULT);
SELECT * FROM t_default;
id|c
--|---
1|100

我们在 VALUES 子句中为 t_default 表的所有字段都指定了数据,此时可以省略表名之后的字段名列表。

插入多行记录

INSERT INTO … VALUES … 语句支持一次插入多行记录。我们只需要在 VALUES 子句中指定多行数据,并且使用逗号进行分隔。例如以下语句一次增加了 3 名员工:

INSERT INTO employee (emp_name, sex, dept_id, manager, hire_date,
job_id, salary, bonus, email, comments,
create_by, create_ts, update_by, update_ts)
VALUES ('李四', '女', 5, 18, '2021-06-06',
10, 6000, NULL, 'lisi@shuguo.com', NULL,
'Admin', CURRENT_TIMESTAMP, NULL, NULL),
('王五', '男', 5, 18, '2021-06-06',
10, 6000, NULL, 'lisi@shuguo.com', NULL,
'Admin', CURRENT_TIMESTAMP, NULL, NULL),
('赵六', '女', 5, 18, '2021-06-06',
10, 6000, NULL, 'lisi@shuguo.com', NULL,
'Admin', CURRENT_TIMESTAMP, NULL, NULL);

提示:Oracle 23c 开始支持多行插入语法。

复制数据

第二种插入语法通过 SELECT 语句得到一个查询结果,然后将该结果插入目标表。我们创建一个新的测试表 emp_devp:

CREATE TABLE emp_devp
( emp_id INTEGER NOT NULL PRIMARY KEY
, emp_name VARCHAR(50) NOT NULL
, sex VARCHAR(10) NOT NULL
, dept_id INTEGER NOT NULL
, manager INTEGER
, hire_date DATE NOT NULL
, job_id INTEGER NOT NULL
, salary NUMERIC(8,2) NOT NULL
, bonus NUMERIC(8,2)
, email VARCHAR(100) NOT NULL
);

emp_devp 表的字段定义来自 employee 表,我们用它来存储复制后的数据。

以下示例将“研发部”的员工信息复制到 emp_devp 表中:

INSERT INTO emp_devp(emp_id, emp_name, sex, dept_id, manager,
hire_date, job_id, salary, bonus, email)
SELECT e.emp_id, e.emp_name, e.sex, e.dept_id, e.manager,
e.hire_date, e.job_id, e.salary, e.bonus, e.email
FROM employee e
JOIN department d ON (d.dept_id = e.dept_id)
WHERE dept_name = '研发部';

如果我们单独执行以上语句中的 SELECT 子句,可以预览复制的源数据。以上语句执行成功之后,我们可以验证一下 emp_devp 表中的数据:

SELECT COUNT(*) 
FROM emp_devp;

COUNT(*)
--------
9

“研发部”9 名员工的信息都被复制到了 emp_devp 表中。

更新数据

SQL 标准使用 UPDATE 语句更新表中的数据。

单表更新

UPDATE 语句的基本语法如下:

UPDATE t
SET col1 = expr1,
col2 = expr2,
...
[WHERE condition];

其中 t 是更新操作的目标表,SET 子句指定了需要更新的列和更新后的值,多个字段使用逗号进行分隔。如果指定了 WHERE 子句,只有满足条件的数据行才会被更新。如果没有指定条件,将会更新表中的所有数据行,这一点需要小心。

例如,以下语句将会更新 emp_devp 表中“赵云”的月薪和奖金:

UPDATE emp_devp
SET salary = salary + 1000,
bonus = 8000
WHERE emp_name = '赵云';

我们在 WHERE 子句中指定了姓名为“赵云”,因此不会更新其他的员工。以上语句执行成功之后,我们可以验证一下数据:

SELECT emp_name AS "姓名", salary AS "月薪", bonus AS "奖金"
FROM emp_devp
WHERE emp_name = '赵云';

姓名|月薪 |奖金
---|--------|-------
赵云|16000.00|8000.00

“赵云”的月薪增加了 1000 元,奖金增加为 8000 元。

提示:数据库在更新数据时也会执行完整性约束校验,确保不会产生违反约束的数据。

关联更新

除直接指定更新后的字段值外,我们也可以通过一个关联子查询获取更新后的数据。例如,以下语句通过关联 employee 表获得更新 emp_devp 表的源数据:

-- Oracle、PostgreSQL 以及SQLite
UPDATE emp_devp
SET (salary, bonus, email) = (SELECT salary, bonus, email
FROM employee e
WHERE e.emp_id = emp_devp.emp_id);

我们在 SET 子句中将多个需要被更新的字段使用括号组合在一起,并且通过一个关联子查询从 employee 表中得到员工的相应数据。

对于 MySQL 和 Microsoft SQL Sever,我们需要为 SET 子句中的每个字段分别指定一个关联子查询,因为它们不支持多个字段的组合更新。

另外,一些数据库中也可以使用 UPDATE JOIN 语句连接其他表,进行数据更新。例如:

-- MySQL
UPDATE emp_devp ed
JOIN employee e ON (e.emp_id = ed.emp_id)
SET ed.salary = e.salary,
ed.bonus = e.bonus,
ed.email = e.email;

-- Microsoft SQL Server
UPDATE emp_devp
SET salary = e.salary,
bonus = e.bonus,
email = e.email
FROM emp_devp ed
JOIN employee e ON (e.emp_id = ed.emp_id);

-- Oracle 23c、PostgreSQL、SQLite
UPDATE emp_devp AS ed
SET salary = e.salary,
bonus = e.bonus,
email = e.email
FROM employee e
WHERE e.emp_id = ed.emp_id;

删除数据

SQL 标准使用 DELETE 语句删除表中的数据。

单表删除

DELETE 语句的基本语法如下:

DELETE FROM t
[WHERE conditions];

其中 t 是删除操作的目标表。如果指定了 WHERE 子句,只有满足条件的数据行才会被删除。如果没有指定条件,将会删除表中所有的数据行,这一点需要小心。

例如,以下语句将会删除员工表中的“张三”、“李四”、“王五”以及“赵六”:

-- SELECT *
DELETE
FROM employee
WHERE emp_name IN ('张三', '李四', '王五', '赵六');

在执行删除语句之前,我们可以使用相应的SELECT语句确认将要删除的数据。

关联删除

DELETE 语句也可以像 UPDATE 语句一样通过子查询获取需要删除的数据。例如:

-- SELECT *
DELETE
FROM emp_devp
WHERE emp_id IN (SELECT emp_id FROM employee);

以上语句可以删除 emp_devp 表中 emp_id 出现在员工表的所有数据。

同样,一些数据库中也可以使用 DELETE JOIN 语法连接其他表进行数据删除。例如:

-- MySQL
DELETE ed
FROM emp_devp ed
JOIN employee e ON (ed.emp_id = e.emp_id);

-- Oracle 23c、PostgreSQL
DELETE
FROM emp_devp ed
USING employee e
WHERE ed.emp_id = e.emp_id;

快速删除全表数据

如果我们想要删除表中的全部数据,数据量比较少时可以直接使用 DELETE 语句,但是这种方式对于数据量很大的表所需的时间比较长。此时,我们可以考虑使用快速删除全表数据的 TRUNCATE 语句。

例如,以下语句可以快速删除 emp_devp 表中的全部数据,也称为截断 emp_devp 表:

-- Oracle、MySQL、Microsoft SQL Server以及PostgreSQL
TRUNCATE TABLE emp_devp;

SQLite 没有提供 TRUNCATE 语句,不过它对 DELETE 语句进行了优化,如果我们不指定 WHERE 子句,实际的效果等同于 TRUNCATE 语句。

DELETE 和 TRUNCATE 语句都可以用于删除数据,但是这两种删除方式存在一些区别:

  • DELETE 语句通过 WHERE 子句删除指定的数据行,如果不指定过滤条件将会删除所有的数据。DELETE 属于数据操作语言(DML),删除数据后可以选择提交或者回滚,如果删除的数据较多时速度比较慢。

  • TRUNCATE 语句用于快速删除表中的所有数据,并且释放表的存储空间。TRUNCATE 属于数据定义语言(DDL),删除数据时默认提交,无法回滚。TRUNCATE 语句相当于删除并重建表,通常执行速度很快。

合并数据

SQL 标准于 2003 年增加了一个新的数据操作语句:MERGE(合并),它可以同时完成 INSERT 语句和 UPDATE 语句,甚至 DELETE 语句的操作。

标准合并语句

目前 Oracle、Microsoft SQL Server 以及 PostgreSQL 实现了 MERGE 语句,它的基本语法如下:

-- Oracle、Microsoft SQL Server 以及 PostgreSQL
MEGRE INTO target_table [AS t_alias]
USING source_table [AS s_alias]
ON (conditions)
WHEN MATCHED THEN
UPDATE
SET col1 = expr1,
col2 = expr2,
...
WHEN NOT MATCHED THEN
INSERT (col1, col2, ...)
VALUES (expr1, expr2, ...);

其中 target_table 是合并操作的目标表。USING 子句指定了数据源,可以是一个表或者查询语句。ON 子句指定了数据合并的条件,通常使用主键或者唯一键相等作为合并的条件。

对于数据源中的每条记录,如果目标表中存在匹配的记录则执行 WHEN MATCHED THEN 分支的更新操作,如果目标表中不存在匹配的记录则执行 WHEN NOT MATCHED THEN 分支的插入操作。

以下示例使用 MERGE 语句将员工表中“研发部”的员工信息合并到 emp_devp 表中:

-- Oracle、Microsoft SQL Server 以及 PostgreSQL
MERGE INTO emp_devp t
USING (SELECT emp_id, emp_name, sex, dept_id, manager,
hire_date, job_id, salary, bonus, email
FROM employee
WHERE dept_id = 4) s
ON (t.emp_id = s.emp_id)
WHEN MATCHED THEN
UPDATE
SET t.emp_name = s.emp_name, t.sex = s.sex,
t.dept_id = s.dept_id, t.manager = s.manager,
t.hire_date = s.hire_date, t.job_id = s.job_id,
t.salary = s.salary, t.bonus = s.bonus,
t.email = s.email
WHEN NOT MATCHED THEN
INSERT (emp_id, emp_name, sex, dept_id, manager,
hire_date, job_id, salary, bonus, email)
VALUES (s.emp_id, s.emp_name, s.sex, s.dept_id, s.manager,
s.hire_date, s.job_id, s.salary, s.bonus, s.email);

以上合并操作的判断条件为数据源和目标表中的 emp_id 是否相等,如果相等则更新目标表中的数据,否则插入数据到目标表。第一次运行以上语句时,emp_devp 表中没有任何数据,因此对于数据源中的每条记录都会执行 WHEN NOT MATCHED THEN 分支,也就是插入新的数据。

以上语句执行成功之后,我们可以查看合并后的数据:

SELECT emp_id, emp_name
FROM emp_devp;

emp_id|emp_name
------|--------
9|赵云
10|廖化
11|关平
12|赵氏
13|关兴
14|张苞
15|赵统
16|周仓
17|马岱

接下来我们修改 emp_devp 表中的某些数据:

DELETE
FROM emp_devp
WHERE emp_name = '赵云';

UPDATE emp_devp
SET salary = 5000,
email = 'liaohua@shuguo.net'
WHERE emp_name = '廖化';

然后我们再次运行上面的 MERGE 语句。此时,对于数据源中的“赵云”将会执行 WHEN NOT MATCHED THEN 分支插入记录,对于数据源中的“廖化”将会执行 WHEN MATCHED THEN 分支的更新目标表中的记录。

对于 MERGE 语句,我们也可以只定义更新操作或者插入操作。例如:

-- Oracle、Microsoft SQL Server 以及 PostgreSQL
MERGE INTO emp_devp t
USING (SELECT emp_id, emp_name, sex, dept_id, manager,
hire_date, job_id, salary, bonus, email
FROM employee
WHERE dept_id = 4) s
ON (t.emp_id = s.emp_id)
WHEN NOT MATCHED THEN
INSERT (emp_id, emp_name, sex, dept_id, manager,
hire_date, job_id, salary, bonus, email)
VALUES (s.emp_id, s.emp_name, s.sex, s.dept_id, s.manager,
s.hire_date, s.job_id, s.salary, s.bonus, s.email);

以上语句只在没有找到匹配数据时插入新的记录,不会在找到匹配数据时更新已有的记录 。

另外,MERGE 语句还支持 DELETE 子句,可以用于删除目标表中匹配的数据。例如:

-- Oracle
MERGE INTO emp_devp t
USING (SELECT emp_id, emp_name, sex, dept_id, manager,
hire_date, job_id, salary, bonus, email
FROM employee
WHERE dept_id = 4) s
ON (t.emp_id = s.emp_id)
WHEN MATCHED THEN
UPDATE
SET t.emp_name = s.emp_name, t.sex = s.sex,
t.dept_id = s.dept_id, t.manager = s.manager,
t.hire_date = s.hire_date, t.job_id = s.job_id,
t.salary = s.salary, t.bonus = s.bonus,
t.email = s.email
DELETE WHERE t.emp_name = '赵氏'
WHEN NOT MATCHED THEN
INSERT (emp_id, emp_name, sex, dept_id, manager,
hire_date, job_id, salary, bonus, email)
VALUES (s.emp_id, s.emp_name, s.sex, s.dept_id, s.manager,
s.hire_date, s.job_id, s.salary, s.bonus, s.email);

我们在 WHEN MATCHED THEN 分支增加了一个 DELETE 子句和 WHERE 条件。如果运行以上语句,emp_devp 表中姓名为“赵氏”的员工记录将会被删除。

Microsoft SQL Server 和 PostgreSQL 也支持 DELETE 子句,不过语法和 Oracle 略有不同:

-- Microsoft SQL Server、PostgreSQL 
MERGE INTO emp_devp t
USING (SELECT emp_id, emp_name, sex, dept_id, manager,
hire_date, job_id, salary, bonus, email
FROM employee
WHERE dept_id = 4) s
ON (t.emp_id = s.emp_id)
WHEN MATCHED AND t.emp_name = '赵氏' THEN
DELETE
WHEN MATCHED THEN
UPDATE
SET t.emp_name = s.emp_name, t.sex = s.sex,
t.dept_id = s.dept_id, t.manager = s.manager,
t.hire_date = s.hire_date, t.job_id = s.job_id,
t.salary = s.salary, t.bonus = s.bonus,
t.email = s.email
WHEN NOT MATCHED THEN
INSERT (emp_id, emp_name, sex, dept_id, manager,
hire_date, job_id, salary, bonus, email)
VALUES (s.emp_id, s.emp_name, s.sex, s.dept_id, s.manager,
s.hire_date, s.job_id, s.salary, s.bonus, s.email);

我们定义了 2 个 WHEN MATCHED THEN 分支,其中第一个分 MATCHED 分支指定了 DELETE 操作和条件。如果运行以上语句,emp_devp 表中姓名为“赵氏”的员工记录将会被删除。

非标准合并语句

MySQL 和 SQLite 没有提供标准 MERGE 语句,不过我们可以使用专有的语法实现合并操作。例如:

-- MySQL
INSERT INTO emp_devp(emp_id, emp_name, sex, dept_id, manager,
hire_date, job_id, salary, bonus, email)
SELECT emp_id, emp_name, sex, dept_id, manager,
hire_date, job_id, salary, bonus, email
FROM employee s
WHERE dept_id = 4
ON DUPLICATE KEY UPDATE
emp_name = s.emp_name, sex = s.sex,
dept_id = s.dept_id, manager = s.manager,
hire_date = s.hire_date, job_id = s.job_id,
salary = s.salary, bonus = s.bonus,
email = s.email;

-- PostgreSQL和SQLite
INSERT INTO emp_devp(emp_id, emp_name, sex, dept_id, manager,
hire_date, job_id, salary, bonus, email)
SELECT emp_id, emp_name, sex, dept_id, manager,
hire_date, job_id, salary, bonus, email
FROM employee s
WHERE dept_id = 4
ON CONFLICT(emp_id) DO UPDATE
SET emp_name = EXCLUDED.emp_name, sex = EXCLUDED.sex,
dept_id = EXCLUDED.dept_id, manager = EXCLUDED.manager,
hire_date = EXCLUDED.hire_date, job_id = EXCLUDED.job_id,
salary = EXCLUDED.salary, bonus = EXCLUDED.bonus,
email = EXCLUDED.email;

MySQL使用 ON DUPLICATE KEY UPDATE 子句合并数据,插入数据时如果主键或者唯一索引出现重复值则执行更新操作。这种专有语法不支持 DELETE 子句。

PostgreSQL 和 SQLite 使用 ON CONFLICT(emp_id) DO UPDATE 子句合并数据,插入数据时如果 emp_id 出现重复值则执行更新操作,EXCLUDED 代表了数据源中的记录。这种专有语法不支持 DELETE 子句。

除此之外,MySQL 和 SQLite 还提供了 REPLACE 语句,也可以实现数据合并或者替换的功能。

外键约束与级联操作

违反外键约束

如果 DML 语句违反了外键约束,数据库会返回错误并取消数据操作。例如:

-- 违反外键约束,职位不存在
INSERT INTO employee (emp_name, sex, dept_id, manager, hire_date,
job_id, salary, bonus, email, comments,
create_by, create_ts, update_by, update_ts)
VALUES ('马超', '男', 5, 18, CURRENT_DATE, -- Microsoft SQL Server 需要替换该函数
11, 6000, NULL, 'machao@shuguo.com', NULL,
'Admin', CURRENT_TIMESTAMP, NULL, NULL);

以上语句在插入数据时违反了外键约束,因为 job_id=11 的记录在 job 表中不存在,我们不能给员工分配一个不存在的职位。

注意:如果使用SQLite,我们需要在编译时启用外键约束支持,并且执行PRAGMA foreign_keys = ON;命令启用外键约束,具体信息可以参考官方文档。

除了插入操作之外,数据库的更新和删除操作同样需要遵循外键约束。例如:

-- 违反外键约束,职位不存在
UPDATE employee
SET job_id = 11
WHERE emp_id = 1;

-- 违反外键约束,存在子记录
DELETE
FROM job
WHERE job_id = 1;

UPDATE 语句将员工的职位设置为一个不存在的职位,违反了外键约束。DELETE 语句删除了一个职位,同样会导致员工表中的记录指向了一个不存在的职位。

提示:外键约束可以防止我们的误操作导致数据不一致,从而维护数据的完整性。

级联更新和删除

一般情况下,子表中的外键约束引用的都是父表中的主键字段,主键字段通常不需要进行更新,或者说我们应该避免使用可能被更新的字段作为主键。

如果我们需要更新父表中的主键字段,或者删除父表中的记录,应该同时对子表中的数据进行更新或者删除。为了方便这一操作,数据库提供了级联更新和级联删除的功能。

我们首先创建两个测试表:

CREATE TABLE t_parent(id INTEGER PRIMARY KEY);
INSERT INTO t_parent(id) VALUES (1);

CREATE TABLE t_child(
id INTEGER PRIMARY KEY,
pid INTEGER NOT NULL,
CONSTRAINT fk1 FOREIGN KEY (pid) REFERENCES t_parent(id)
ON UPDATE CASCADE -- Oracle不支持该选项
ON DELETE CASCADE
);
INSERT INTO t_child(id, pid) VALUES (1, 1);
INSERT INTO t_child(id, pid) VALUES (2, 1);

其中 t_parent 是父表,t_child 是子表,子表的 pid 字段引用了父表的主键字段 id。外键定义中的 ON UPDATE CASCADE 子句表示更新父表主键时级联更新子表中的记录,ON DELETE CASCADE 子句表示删除父表记录时级联删除子表中的记录。

Oracle 不支持 ON UPDATE CASCADE 选项。

以下示例验证了级联更新的效果:

-- MySQL、Microsoft SQL Server、PostgreSQL以及SQLite
UPDATE t_parent
SET id = 3
WHERE id = 1;

SELECT * FROM t_child;

id|pid
--|---
1| 3
2| 3

从查询结果可以看出,更新 t_parent 表中的主键会级联更新 t_child 表中的外键字段。

对于 Oracle 数据库,如果我们执行上面的 UPDATE 语句,将会违反外键约束。

最后我们验证一下级联删除的效果:

DELETE 
FROM t_parent
WHERE id = 3;

SELECT * FROM t_child;

id|pid
--|---

从查询结果可以看出,删除 t_parent 表中的记录会级联删除 t_child 表中的相应记录。对于 Oracle 数据库,我们应该删除 id 为 1 的记录。

SQL标准对于外键定义中的 ON UPDATE和ON DELETE 子句提供了以下选项:

  • NO ACTION,如果父表上的UPDATE或者DELETE语句违反外键约束则返回错误,数据库在事务提交(COMMIT)时检查是否违反约束。

  • RESTRICT,如果父表上的UPDATE或者DELETE语句违反外键约束则返回错误,数据库在语句执行时立即检查是否违反约束。

  • CASCADE,如果在父表上执行UPDATE或者DELETE语句,级联更新或者删除子表上的记录。

  • SET NULL,如果在父表上执行UPDATE或者DELETE语句,将子表中的外键字段设置为NULL。

  • SET DEFAULT,如果在父表上执行UPDATE或者DELETE语句,将子表中的外键字段设置为默认值。

PostgreSQL 和 SQLite 支持全部的选项。

MySQL 不支持 SET DEFAULT 选项,并且 NO ACTION 和 RESTRICT 的作用相同,都是在语句执行时立即检查。

Microsoft SQL Server 不支持 RESTRICT 选项。

Oracle 只支持 ON UPDATE 子句的 NO ACTION 选项以及 ON DELETE 子句的 NO ACTION、CASCADE 以及 SET NULL 选项。

请使用浏览器的分享功能分享到微信等