SQL 约束(建议收藏)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观

在数据库设计中,"SQL 约束" 是确保数据完整性和一致性的重要工具。无论是开发简单的学生信息管理系统,还是复杂的电商平台,合理使用约束都能避免数据混乱,提升系统可靠性。本文将通过生活化的比喻和实际案例,系统讲解 SQL 约束的核心概念与应用场景,帮助读者快速掌握这一关键技能。


主键约束(Primary Key)

定义与作用

主键约束是数据库中唯一标识一条记录的"身份证"。它确保每条记录的主键值既不重复也不为空,如同每个人都有唯一的身份证号码。例如,在用户表中,user_id 通常被设为主键,避免出现两个用户拥有相同的唯一标识。

代码示例

CREATE TABLE users (  
    user_id INT PRIMARY KEY,  
    username VARCHAR(50),  
    email VARCHAR(100)  
);  

如果尝试插入两条 user_id 为 1 的记录,数据库会直接报错:

INSERT INTO users (user_id, username)  
VALUES (1, 'Alice'), (1, 'Bob');  
-- Error: Duplicate entry '1' for key 'PRIMARY'  

实际应用

主键的设计需考虑业务场景。例如电商平台的商品表,若商品编码有唯一性且永不重复,可直接设为 product_id 主键;若需自动生成唯一值,可使用自增字段:

CREATE TABLE products (  
    product_id INT AUTO_INCREMENT PRIMARY KEY,  
    product_name VARCHAR(255)  
);  

外键约束(Foreign Key)

数据关联的"纽带"

外键约束用于建立表与表之间的关系,确保引用完整性。假设有一个订单表 orders 需关联用户表 users,外键 user_id 必须存在于 users 表的 user_id 列中。这就像家庭成员之间的关系:孩子必须属于某个家庭,不能凭空存在。

创建与验证

CREATE TABLE orders (  
    order_id INT PRIMARY KEY,  
    user_id INT,  
    FOREIGN KEY (user_id) REFERENCES users(user_id)  
);  

若尝试插入一个 user_id 不存在的订单:

INSERT INTO orders (order_id, user_id)  
VALUES (1001, 999); -- 假设 users 表中没有 user_id=999  
-- Error: Cannot add or update a child row  

级联操作

外键可配合 ON DELETEON UPDATE 实现级联操作:

ALTER TABLE orders  
ADD CONSTRAINT fk_user  
FOREIGN KEY (user_id)  
REFERENCES users(user_id)  
ON DELETE CASCADE  
ON UPDATE CASCADE;  

当删除用户时,其关联订单会自动删除,避免数据残留。


唯一约束(Unique Constraint)

避免重复的"过滤网"

唯一约束确保某一列(或组合列)的值不重复,但允许 NULL 值。例如,用户表中的邮箱地址需要唯一性,防止重复注册:

CREATE TABLE users (  
    user_id INT PRIMARY KEY,  
    email VARCHAR(100) UNIQUE  
);  

若尝试插入相同邮箱:

INSERT INTO users (user_id, email)  
VALUES (2, 'alice@example.com'), (3, 'alice@example.com');  
-- Error: Duplicate entry 'alice@example.com' for key 'email_UNIQUE'  

组合唯一约束

多个字段的组合也可设为唯一,例如课程表中的 course_codesemester 组合需唯一:

CREATE TABLE courses (  
    course_id INT PRIMARY KEY,  
    course_code VARCHAR(10),  
    semester VARCHAR(20),  
    UNIQUE (course_code, semester)  
);  

非空约束(NOT NULL)

数据完整性"守护者"

非空约束强制字段必须包含值,避免关键信息缺失。例如,用户表的 usernameemail 不应为空:

CREATE TABLE users (  
    user_id INT PRIMARY KEY,  
    username VARCHAR(50) NOT NULL,  
    email VARCHAR(100) NOT NULL  
);  

尝试插入缺少 username 的记录会失败:

INSERT INTO users (user_id, email)  
VALUES (4, 'bob@example.com');  
-- Error: Field 'username' doesn't have a default value  

与默认值的结合

若字段需要非空但允许默认值,可结合 DEFAULT 约束:

CREATE TABLE posts (  
    post_id INT PRIMARY KEY,  
    content TEXT NOT NULL,  
    status VARCHAR(10) NOT NULL DEFAULT 'draft'  
);  

检查约束(CHECK Constraint)

数据范围的"守门人"

检查约束通过逻辑条件限制列的取值范围。例如,年龄字段需在 18-100 岁之间:

CREATE TABLE users (  
    user_id INT PRIMARY KEY,  
    age INT CHECK (age BETWEEN 18 AND 100)  
);  

插入 age=17 的记录会报错:

INSERT INTO users (user_id, age)  
VALUES (5, 17);  
-- Error: Check constraint 'age' is violated.  

跨字段验证

部分数据库(如 PostgreSQL)支持跨列条件:

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

默认约束(DEFAULT Constraint)

自动填充的"智能助手"

默认约束为字段指定默认值,简化数据录入。例如,订单表的 created_at 可自动设为当前时间:

CREATE TABLE orders (  
    order_id INT PRIMARY KEY,  
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP  
);  

插入记录时无需手动填写时间:

INSERT INTO orders (order_id)  
VALUES (1002);  
-- created_at 自动设为插入时的时间  

结合业务逻辑

默认值可配合其他约束使用,例如用户状态默认为 "active":

CREATE TABLE users (  
    user_id INT PRIMARY KEY,  
    status VARCHAR(10) DEFAULT 'active' NOT NULL  
);  

约束的添加与修改

动态调整约束

已存在的表可通过 ALTER TABLE 添加约束:

-- 添加非空约束  
ALTER TABLE users  
MODIFY COLUMN email VARCHAR(100) NOT NULL;  

-- 添加外键约束  
ALTER TABLE orders  
ADD CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES users(user_id);  

删除约束

ALTER TABLE orders  
DROP FOREIGN KEY fk_user;  

实战案例:设计学生选课系统

表结构设计

CREATE TABLE students (  
    student_id INT PRIMARY KEY,  
    name VARCHAR(50) NOT NULL,  
    email VARCHAR(100) UNIQUE  
);  

CREATE TABLE courses (  
    course_id INT PRIMARY KEY,  
    course_code VARCHAR(10) NOT NULL,  
    credits INT CHECK (credits BETWEEN 1 AND 6)  
);  

CREATE TABLE enrollments (  
    enrollment_id INT PRIMARY KEY,  
    student_id INT,  
    course_id INT,  
    grade CHAR(2),  
    FOREIGN KEY (student_id) REFERENCES students(student_id),  
    FOREIGN KEY (course_id) REFERENCES courses(course_id),  
    UNIQUE (student_id, course_id)  -- 同一学生不可重复选同一课程  
);  

数据验证示例

尝试插入无效数据时:

INSERT INTO courses (course_id, course_code, credits)  
VALUES (101, 'MATH101', 7);  
-- Error: Check constraint 'credits' is violated.  

结论

通过合理运用 SQL 约束,开发者可以构建出更健壮、可靠的数据库系统。从主键的唯一标识,到外键的关联验证,再到检查约束的数据范围控制,每种约束都在保障数据的"纯净性"。建议在设计初期就规划好约束策略,并通过实际案例反复验证。随着项目复杂度的提升,这些约束将成为维护数据质量的坚实屏障。

掌握 SQL 约束不仅需要理论理解,更需通过动手实践加深记忆。尝试为现有项目添加约束,观察数据行为的变化,逐步培养数据库设计的"约束思维"。记住,良好的约束设计如同为数据穿上"防护衣",让系统在应对海量操作时依然稳定如初。

最新发布