CHECK
CHECK 约束用于验证列值是否满足指定条件,不满足则拒绝插入或更新。
CHECK 后面跟一个布尔表达式,插入或更新数据时,如果表达式的值是 FALSE,操作就被拒绝。表达式可以引用当前行的任意列,常见的规则有:年龄必须大于 0、价格不能为负数、绩效分数在 0 到 100 之间、开始日期必须早于结束日期。
MySQL 8.0.16 及之后的版本完整支持 CHECK,早期版本虽然语法上接受但会悄悄忽略——这一点要特别注意,如果你的 MySQL 版本太老,CHECK 写了等于没写,业务规则还是得靠应用层兜底。
什么场景需要它?业务规则如果不放在数据库层面,只靠应用代码校验,总有漏网之鱼——可能是一个直接操作数据库的后台脚本绕过了校验,也可能是另一个微服务不知道这层规则。CHECK 作为数据库的最后一道防线,不管数据从哪个入口进来,都得过这一关。飞翔科技的工资系统里,基本工资必须大于 0、绩效分数不能超过 100——这些规则交给 CHECK 比交给程序员更靠谱。
标准写法:
-- 列级 CHECK
CREATE TABLE 表名 (
列名 数据类型 CHECK (条件表达式)
);
-- 表级 CHECK(可引用多列)
CREATE TABLE 表名 (
列名1 数据类型,
列名2 数据类型,
CONSTRAINT 约束名 CHECK (条件表达式)
);
以飞翔科技为例。员工表的多项业务规则用 CHECK 兜底:
CREATE TABLE employees (
emp_id INT PRIMARY KEY,
emp_name VARCHAR(50) NOT NULL,
age TINYINT CHECK (age >= 18),
performance_score INT CHECK (performance_score BETWEEN 0 AND 100),
basic_salary DECIMAL(10,2) NOT NULL CHECK (basic_salary > 0),
performance_bonus DECIMAL(10,2) CHECK (performance_bonus >= 0),
company_name VARCHAR(100) DEFAULT '广州飞翔科技'
);
-- 年龄 16 岁——未成年员工,不符合劳动法,数据库拒绝
INSERT INTO employees (emp_id, emp_name, age, performance_score, basic_salary)
VALUES (10001, '翱翔', 16, 100, 8888.88);
-- Error: Check constraint is violated
-- 各项数据都在合理范围内,顺利通过
INSERT INTO employees (emp_id, emp_name, age, performance_score, basic_salary, performance_bonus)
VALUES (10001, '翱翔', 28, 100, 8888.88, 18888.88);
四条 CHECK 约束像四道安检一样依次检查:年龄够不够 18、绩效有没有超过 100、工资是不是正数、奖金是不是负数。一条不满足,整条记录都插不进来——这种"要么全过,要么全拒"的原子性保护,正是数据库约束最大的价值。