SQL 结构定义:约束

在数据库设计中,约束(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)

主键(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);

  

外键(FOREIGN KEY)

外键是建立两个表之间关联的字段,它指向另一个表的主键,用于保障 “参照完整性”。

其核心特性如下:

  • 外键字段的值必须是关联表主键的已存在值(或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; -- 禁止删除有订单的用户

 

唯一约束(UNIQUE)

唯一约束用于确保字段(或组合字段)的值在表中唯一,与主键的区别如下:

  • 主键:一个表仅能有一个,且不允许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);

 

检查约束(CHECK)

检查约束用于限定字段的取值范围或满足的条件,强制数据符合业务规则。例如:

  • 年龄必须大于 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;

 

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
其他应用
公众号