CHECK 约束(Check Constraint)是 SQL 中用于保证数据合法性和业务规则一致性的一种约束机制。它允许你为列或列组合定义一个布尔条件表达式,只有当表达式结果为 TRUE 时,数据才能被插入或更新。

CHECK 约束是做什么的?

它的作用是:

  • ✅ 限制列中允许存储的数据范围
  • ✅ 防止不合法、不合理的数据写入数据库
  • ✅ 将业务规则前移到数据库层,减少程序漏洞

例如:

  • 年龄不能小于 18
  • 金额必须大于 0
  • 状态值只能是指定的几个枚举值

基本语法

列级 CHECK

1
column_name data_type CHECK (condition)

表级 CHECK(推荐,更清晰)

1
CHECK (condition)

只要 condition 结果不是 TRUE,插入或更新都会失败。

基础示例

1️⃣ 简单条件

员工年龄必须 ≥ 18:

1
2
3
4
5
CREATE TABLE employees (
id INT PRIMARY KEY,
name VARCHAR(100),
age INT CHECK (age >= 18)
);

尝试插入非法数据会失败:

1
2
INSERT INTO employees VALUES (1, 'Tom', 16);
-- ❌ CHECK constraint violation

2️⃣ 多个列分别约束

1
2
3
4
5
6
CREATE TABLE employees (
id INT PRIMARY KEY,
name VARCHAR(100),
age INT CHECK (age >= 18),
salary DECIMAL CHECK (salary > 0)
);

3️⃣ 组合条件(列之间的关系)

1
2
3
4
5
6
7
CREATE TABLE employees (
id INT PRIMARY KEY,
name VARCHAR(100),
age INT,
salary DECIMAL,
CHECK (age >= 18 AND salary > 0)
);

这种写法更适合复杂规则,可读性也更好。

常用的表达式类型

1️⃣ 比较运算符

1
2
3
4
5
6
=   等于
<> 或 != 不等于
> 大于
< 小于
>= 大于等于
<= 小于等于

示例:

1
2
3
CHECK (age >= 18)
CHECK (price > 0)
CHECK (score <> 0)

2️⃣ 逻辑运算符

1
2
3
AND   并且
OR 或
NOT 取反

示例:

1
2
3
CHECK (age BETWEEN 18 AND 60)
CHECK (status = 'active' OR status = 'pending')
CHECK (NOT (is_deleted = 1))

3️⃣ 范围与集合

BETWEEN

1
2
CHECK (age BETWEEN 18 AND 60)
CHECK (discount BETWEEN 0 AND 1)

IN / NOT IN

1
2
3
CHECK (status IN ('active', 'inactive', 'pending'))
CHECK (role IN ('admin', 'user'))
CHECK (day_of_week IN (1,2,3,4,5,6,7))

4️⃣ NULL 相关(非常重要

CHECK 对 NULL 的行为容易被忽略

规则是:

如果 CHECK 表达式结果为 UNKNOWN(NULL),约束是通过的

例如:

1
CHECK (age >= 18)

age IS NULL 时:

  • 表达式结果是 NULL
  • 不会触发 CHECK 错误

如果你不允许 NULL,必须显式写:

1
age INT NOT NULL CHECK (age >= 18)

或:

1
2
CHECK (age IS NOT NULL AND age >= 18)
CHECK (code IS NOT NULL AND code LIKE 'A_%')

5️⃣ 字符串匹配(LIKE / NOT LIKE)

1
2
CHECK (email LIKE '%@%')
CHECK (code LIKE 'A_%'):
符号 含义
% 任意长度的任意字符(包括 0 个)
_ 恰好 1 个任意字符

部分数据库支持正则:

  • MySQL: REGEXP
  • PostgreSQL: ~

6️⃣ 算术运算

  • +

  • -

  • *

  • /

  • % 取模(部分数据库支持)

  • () 括号改变优先级

1
2
3
CHECK (salary > 0)
CHECK (bonus <= salary * 0.5)
CHECK (quantity * price <= 10000)

命名

给 CHECK 约束命名,方便排错和维护:

1
2
3
4
CREATE TABLE employees (
age INT,
CONSTRAINT chk_employee_age CHECK (age >= 18)
);

报错信息会更清晰:

1
violates check constraint "chk_employee_age"

现有表添加 CHECK

已有表也可以后期添加:

1
2
ALTER TABLE employees
ADD CONSTRAINT chk_salary_positive CHECK (salary > 0);

支持情况

数据库 CHECK 是否生效 版本说明 关键限制 / 特点
MySQL ≤ 5.7 ❌ 不生效 语法存在但不会校验 仅解析,不执行
MySQL ≥ 8.0.16 ✅ 生效 真正支持 CHECK 不允许子查询、非确定性函数
PostgreSQL ✅ 始终生效 所有版本 校验严格,功能最完整
SQL Server ✅ 生效 主流版本 语法稳定,限制较多
Oracle ✅ 生效 主流版本 企业级支持