在数据库设计中,约束(Constraint)是保障数据完整性和一致性的核心机制。它能强制数据库遵循预设的规则,避免无效、重复或关联错误的数据进入表中。本文将聚焦 SQL 中最常用的四类约束 —— 主键、外键、唯一约束、检查约束,详细介绍它们的定义、用法和应用场景。
约束(Constraint)是保障数据质量和数据库稳定性的核心机制,其本质是数据库系统为数据表中的数据设定的一系列 “强制性规则限制” —— 这些规则由数据库层面直接强制执行,而非依赖应用程序代码,能从根源上避免无效、混乱或不一致的数据进入系统。
“规则限制” 主要作用如下:
(1)确保数据实体完整性
实体完整性是指数据表中的每一行数据(即一个 “实体”)都必须是唯一且可识别的,不会出现重复或无法定位的记录。最典型的应用就是主键(PRIMARY KEY)约束:它要求主键字段的值非空(NOT NULL)且唯一,确保表中每一行数据都有一个独一无二的标识,比如用户表的user_id、订单表的order_id,通过主键能精准定位到某一条具体数据,避免数据混乱。
(2)保证数据参照完整性
参照完整性用于维护多个数据表之间的关联关系,避免出现 “孤立” 或 “无效关联” 的数据。外键(FOREIGN KEY)约束是实现这一目标的核心:它要求从表(子表)的外键字段值,必须匹配主表(父表)主键字段的有效值。例如,订单表的user_id作为外键关联用户表的user_id,就能保证所有订单都能对应到真实存在的用户,不会出现 “归属不存在用户的订单”,也能防止主表中被关联的记录被随意删除
(3)维持数据域完整性
域完整性聚焦于单个字段的取值有效性,确保字段值符合预设的 “数据域” 规则,避免出现不符合业务逻辑的数据。常见的实现方式包括:
检查约束(CHECK):限定字段的取值范围,比如将年龄字段age限定为 >=0 AND <=150,避免出现负数或不合理的超大值;
非空约束(NOT NULL):强制字段必须填写值,比如用户表的 username 不允许为空;
唯一约束(UNIQUE):保证字段值唯一(但允许空值,与主键不同),比如用户表的 phone 不允许重复。
(4)减少冗余数据,提升数据可靠性和查询效率
约束通过标准化数据规则,从源头减少了冗余、错误、不一致的数据。例如,通过外键约束避免重复存储用户信息,通过检查约束避免无效数据入库;而高质量的数据能直接提升查询效率 —— 数据库无需扫描无效数据,查询语句的执行结果也更精准,同时减少了后续数据清洗、纠错的人力成本,提升了整个数据库系统的可靠性和可维护性。
⚠️注意:所有约束既可以在创建表(CREATE TABLE)时定义,也可以在表创建后通过ALTER TABLE添加/修改。
主键(Primary Key)是用于唯一标识表中每一行记录的字段(或组合字段,即多个字段),是表的 “唯一身份证”。
其核心特性如下:
唯一性:主键值不能重复;
非空性:主键字段不允许为NULL;
一个表仅能有一个主键:可由单个字段构成(单字段主键),也可由多个字段组合(复合主键)。
提示:主键适用于需要唯一标识记录的场景,如用户 ID、商品 ID、订单 ID 等核心字段,是数据库表设计的基础。
(1)创建表时定义单字段主键,如下:
-- 创建用户表,以 user_id 作为主键 CREATE TABLE users ( user_id INT NOT NULL, username VARCHAR(50) NOT NULL, email VARCHAR(100), -- 定义主键 PRIMARY KEY (user_id) );
(2)创建表时定义复合主键,如下:
-- 创建订单明细表,订单ID + 商品ID 组合作为主键 CREATE TABLE order_items ( order_id INT NOT NULL, -- 订单ID product_id INT NOT NULL, -- 商品ID quantity INT NOT NULL, price DECIMAL(10,2) NOT NULL, -- 复合主键:多个字段组合唯一标识记录 PRIMARY KEY (order_id, product_id) );
(3)表创建后添加主键,如下:
-- 先创建无主键的表 CREATE TABLE products ( product_id INT NOT NULL, product_name VARCHAR(100) NOT NULL, price DECIMAL(10,2) ); -- 新增主键约束 ALTER TABLE products ADD CONSTRAINT pk_product_id PRIMARY KEY (product_id);
外键是建立两个表之间关联的字段,它指向另一个表的主键,用于保障 “参照完整性”。
其核心特性如下:
外键字段的值必须是关联表主键的已存在值(或NULL,如果允许)
若关联表中被引用的记录被删除 / 修改,需通过ON DELETE/ON UPDATE指定处理规则(如CASCADE级联删除、RESTRICT禁止操作等);
外键所在表为 “子表”,被引用的表为 “父表”。
常见外键处理规则如下:
CASCADE:父表记录删除 / 修改,子表关联记录同步操作
RESTRICT:若子表有关联记录,禁止操作父表
SET NULL:父表记录删除 / 修改,子表外键字段设为 NULL(需字段允许 NULL)
NO ACTION:同 RESTRICT,仅语法差异
提示:外键用于表间关联场景,如订单表关联用户表(一个用户可有多笔订单)、订单明细表关联订单表 / 商品表,是实现一对一、一对多、多对多关系的核心。
(1)创建表时定义外键,如下:
-- 父表:用户表(已创建,主键为user_id) -- 参考前面 -- 子表:订单表,order_user_id关联用户表的user_id CREATE TABLE orders ( order_id INT NOT NULL PRIMARY KEY, order_user_id INT NOT NULL, order_time DATETIME NOT NULL, total_amount DECIMAL(10,2) NOT NULL, -- 定义外键约束 FOREIGN KEY (order_user_id) REFERENCES users(user_id) -- 规则:若用户被删除,其关联订单也删除 ON DELETE CASCADE -- 规则:若用户ID修改,订单中关联ID同步修改 ON UPDATE CASCADE );
(2)表创建后添加外键,如下:
-- 先创建无外键的订单表 CREATE TABLE orders ( order_id INT NOT NULL PRIMARY KEY, order_user_id INT NOT NULL, order_time DATETIME NOT NULL, total_amount DECIMAL(10,2) NOT NULL ); -- 新增外键约束 ALTER TABLE orders ADD CONSTRAINT fk_orders_user_id FOREIGN KEY (order_user_id) REFERENCES users(user_id) ON DELETE RESTRICT; -- 禁止删除有订单的用户
唯一约束用于确保字段(或组合字段)的值在表中唯一,与主键的区别如下:
主键:一个表仅能有一个,且不允许NULL;
唯一约束:一个表可有多组,允许字段值为NULL(多数数据库允许多个NULL)。
提示:唯一约束适用于需要唯一但非核心标识(主键)的字段,如用户邮箱、手机号、身份证号等,避免重复数据。
(1)创建表时定义唯一约束,如下:
CREATE TABLE users ( user_id INT NOT NULL PRIMARY KEY, username VARCHAR(50) NOT NULL, email VARCHAR(100), phone VARCHAR(20), -- 单字段唯一约束:邮箱唯一 UNIQUE (email), -- 多字段组合唯一:用户名+手机号组合唯一 UNIQUE (username, phone) );
(2)表创建后添加唯一约束,如下:
-- 为users表新增手机号唯一约束 ALTER TABLE users ADD CONSTRAINT uk_users_phone UNIQUE (phone);
检查约束用于限定字段的取值范围或满足的条件,强制数据符合业务规则。例如:
年龄必须大于 0 且小于 150;
订单金额必须大于 0;
性别只能是 “男” 或 “女”。
提示:检查约束适用于需要限定字段取值的业务场景,如金额、年龄、状态等字段的合法性校验。
注意:
部分数据库(如 MySQL 5.6 及之前版本)对CHECK约束仅做语法解析,不实际生效,需通过触发器实现等效功能;
检查约束的条件应简洁,避免复杂逻辑(如子查询),否则会影响插入 / 更新效率。
(1)创建表时定义检查约束,如下:
CREATE TABLE users (
user_id INT NOT NULL PRIMARY KEY,
username VARCHAR(50) NOT NULL,
age INT,
gender VARCHAR(10),
balance DECIMAL(10,2) DEFAULT 0,
-- 检查年龄范围
CHECK (age > 0 AND age < 150),
-- 检查性别取值
CHECK (gender IN ('男', '女', '未知')),
-- 检查余额非负
CHECK (balance >= 0)
);(2)表创建后添加检查约束
-- 为users表新增“用户名长度≥3”的检查约束 ALTER TABLE users ADD CONSTRAINT ck_users_username CHECK (LENGTH(username) >= 3);
如果需要删除已定义的约束,可通过ALTER TABLE实现,如下:
-- 删除主键约束(以users表为例) ALTER TABLE users DROP PRIMARY KEY; -- 删除外键约束 ALTER TABLE orders DROP FOREIGN KEY fk_orders_user_id; -- 删除唯一约束 ALTER TABLE users DROP INDEX uk_users_phone; -- 删除检查约束(MySQL) ALTER TABLE users DROP CHECK ck_users_username;