检查约束核心特性

1. 数据验证:确保列值满足指定条件

2. 表达式支持:可使用各种SQL表达式

3. 多列验证:支持基于表的约束验证多列关系

4. 版本支持:

    MySQL 8.0.16+ 原生支持并强制执行CHECK约束

    早期版本会解析但不强制执行

 

检查约束操作详解

创建表时定义检查约束

单列检查约束:

CREATE TABLE employees (
    emp_id INT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    salary DECIMAL(10,2) CHECK (salary > 0),
    age INT CHECK (age >= 18 AND age <= 65)
);

 

多列组合检查约束:

CREATE TABLE products (
    product_id INT PRIMARY KEY,
    price DECIMAL(10,2),
    discount_price DECIMAL(10,2),
    CHECK (discount_price < price)
);

 

命名约束(推荐):

CREATE TABLE orders (
    order_id INT PRIMARY KEY,
    order_date DATE,
    delivery_date DATE,
    CONSTRAINT chk_delivery_date 
        CHECK (delivery_date >= order_date)
);

 

修改表添加检查约束

ALTER TABLE employees
ADD CONSTRAINT chk_employee_age
CHECK (age >= 18 AND age <= 65);

 

删除检查约束

ALTER TABLE employees
DROP CONSTRAINT chk_employee_age;

 

高级检查约束技术

复杂表达式

CREATE TABLE reservations (
    res_id INT PRIMARY KEY,
    start_date DATE,
    end_date DATE,
    room_type VARCHAR(20),
    CHECK (
        end_date > start_date AND
        (room_type IN ('Deluxe', 'Suite') OR 
         DATEDIFF(end_date, start_date) <= 30)
    )
);

 

正则表达式检查

CREATE TABLE users (
    user_id INT PRIMARY KEY,
    email VARCHAR(100),
    phone VARCHAR(20),
    CONSTRAINT chk_valid_email
        CHECK (email REGEXP '^[A-Za-z0-9._%-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}$'),
    CONSTRAINT chk_valid_phone
        CHECK (phone REGEXP '^[0-9]{10,15}$')
);

 

条件检查约束

CREATE TABLE inventory (
    item_id INT PRIMARY KEY,
    quantity INT,
    status VARCHAR(20),
    CHECK (
        (status = 'In Stock' AND quantity > 0) OR
        (status = 'Out of Stock' AND quantity = 0) OR
        (status = 'Backorder')
    )
);

 

检查约束最佳实践

1. 命名规范:使用`chk_表名_列名`的命名约定

2. 业务规则:

    实现领域特定规则(如"折扣价必须低于原价")

    验证数据格式(邮箱、电话等)

3. 性能考虑:

    复杂表达式可能影响写入性能

    避免在检查约束中使用子查询

4. 与应用层验证结合:

    检查约束作为最后的数据防线

    应用层应提前验证减少数据库压力

 

实际应用示例

银行账户系统:

CREATE TABLE accounts (
    account_id INT PRIMARY KEY,
    account_type VARCHAR(20),
    balance DECIMAL(15,2),
    min_balance DECIMAL(15,2),
    CHECK (
        (account_type = 'Savings' AND balance >= min_balance) OR
        (account_type = 'Checking' AND balance >= -1000)
    )
);

 

学校管理系统:

CREATE TABLE student_grades (
    record_id INT PRIMARY KEY,
    student_id INT,
    course_id INT,
    grade VARCHAR(2),
    semester VARCHAR(20),
    CHECK (
        grade IN ('A', 'B', 'C', 'D', 'F', 'I', 'W') AND
        semester REGEXP '^(Spring|Summer|Fall|Winter) 20[0-9]{2}$'
    ),
    UNIQUE (student_id, course_id, semester)
);

 

版本兼容性处理

对于MySQL 8.0.16之前的版本,可通过以下方式模拟检查约束:

1. 使用触发器:

CREATE TRIGGER check_salary BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
    IF NEW.salary <= 0 THEN
        SIGNAL SQLSTATE '45000' 
        SET MESSAGE_TEXT = 'Salary must be positive';
    END IF;
END;

 

2. 使用ENUM类型(适用于有限值集合):

CREATE TABLE tasks (
    task_id INT PRIMARY KEY,
    status ENUM('Pending', 'In Progress', 'Completed')
);
点赞(1)

C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:

一点编程也不会写的:零基础C语言学练课程

解决困扰你多年的C语言疑难杂症特性的C语言进阶课程

从零到写出一个爬虫的Python编程课程

只会语法写不出代码?手把手带你写100个编程真题的编程百练课程

信息学奥赛或C++选手的 必学C++课程

蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程

手把手讲解近五年真题的蓝桥杯辅导课程

Dotcpp在线编译      (登录可减少运行等待时间)