MySQL

约束

MySQL 约束:主键、唯一、非空、检查、默认值与外键;desc/show create 与插入报错实验。

没有约束的表,可以插进 id=null、重复手机号、15 岁的「员工」……约束就是在数据库层给数据「上规矩」。

系列:MySQL 入门到查询 · 第 15 / 17 篇(第 15 天 · 5 月 5 日)
上一篇:多表关联查询
下一篇:备份与实用命令
总目录:系列索引

环境说明

  • 库:train
  • 本篇专用表在文中给出;请按小节 先删再建,避免旧结构干扰
  • 练习数据以本篇 seed 为准

1. 什么是约束

约束(Constraint):对表中某一列(或多列)的数据增加的限制条件。

约束关键字一句话
主键primary key非空 + 唯一;一张表通常一个主键
唯一unique不能重复;多个 NULL 在 MySQL 的 UNIQUE 列里通常是允许的
非空not null不能为空
检查check(条件)值必须满足条件(如 age>=18;MySQL 需 8.0.16+ 才能真正强制)
默认值default 值不给该列值时用默认值
外键foreign key约定两张表的关联(强约束)

2. 建一张「多约束」表

use train;

drop table if exists person;
create table person(
    id    int primary key,
    name  varchar(10) not null,
    sex   varchar(1) default '女',
    age   int check(age>=18),
    phone varchar(11) unique
);

2.1 用 desc / show create 查看

desc person;
show create table person;
列在 desc 里看什么
idNull=NO,Key=PRI
nameNull=NO
sexDefault=女(或相近显示)
phoneKey=UNI
age 的 checkdesc 可能看不到,看 show create table 里的 CONSTRAINT ... CHECK

3. 逐个测约束(插入报错)

3.1 主键:非空且唯一

-- 失败:主键不能为 NULL
insert into person values(null,'张三','男',20,'13112345678');
ERROR 1048 (23000): Column 'id' cannot be null
insert into person values(1,'张三','男',20,'13112345678');

-- 失败:主键重复
insert into person values(1,'李四','女',19,'13212345678');
ERROR 1062 (23000): Duplicate entry '1' for key 'person.PRIMARY'

3.2 非空 not null

-- 失败:name 不能为 NULL
insert into person values(2,null,'女',19,'13212345678');
ERROR 1048 (23000): Column 'name' cannot be null

3.3 默认值 default(易错)

-- 全列插入时,显式写 null 往往就是 null,不一定触发 default
insert into person values(2,'李四',null,19,'13212345678');
select * from person;
-- 推荐:指定列插入,省略 sex,才会用默认值
insert into person(id,name,age,phone) values(3,'王五',21,'13312345678');
select * from person;

口诀:默认值在「没给这一列」时生效;用 insert into 表(列...) values(...) 才能稳定吃到 default。

3.4 检查 check

-- 失败:age < 18
insert into person values(4,'赵六','男',15,'13412345678');
ERROR 3819 (HY000): Check constraint ... is violated.
insert into person values(4,'赵六','男',18,'13412345678');

3.5 唯一 unique

-- 失败:phone 与已有数据重复
insert into person values(5,'钱七','男',20,'13112345678');
ERROR 1062 (23000): Duplicate entry '13112345678' for key ...
insert into person values(5,'钱七','男',20,'13900000005');
select * from person;

4. 自动编号 auto_increment(配合主键)

主键常常由数据库自增,减少手写编号:

drop table if exists auto01;
create table auto01(
    id int primary key auto_increment,
    name varchar(10)
);

insert into auto01 values(null,'张三');
insert into auto01(name) values('李四');
insert into auto01 values(10,'王五');  -- 指定 id 也可以
insert into auto01(name) values('赵六');
select * from auto01;
desc auto01;   -- Key=PRI,Extra 里可见 auto_increment
行为说明
不给 id / 给 null用下一个自动编号
显式给较大 id后续自动编号一般从更大值继续
删除中间行一般不会回填已删编号

规则:auto_increment 通常与 主键 一起用,不能单独当唯一业务号来「保证连续不跳号」。

5. 外键 foreign key

5.1 先分清主表 / 从表

角色例子说明
主表学生表 s01提供被引用的键;课堂常用主键(MySQL 也可引用 UNIQUE 列)
从表课程/成绩表 c01用外键列指向主表
主表 s01(id 主键)  ←──  从表 c01(sid → s01.id)

5.2 语法(写在从表)

constraint 外键名 foreign key(从表列) references 主表名(主表列)

建表顺序:先主后从

use train;

drop table if exists c01;
drop table if exists s01;

create table s01(
    id int primary key,
    name varchar(10)
);

create table c01(
    cid int,
    sid int,
    cname varchar(10),
    constraint s01_id_c01_sid foreign key(sid) references s01(id)
);

show create table c01;

desc c01 中 sid 的 Key 可能显示 MUL;具体外键关系看 show create table c01:

CONSTRAINT `s01_id_c01_sid` FOREIGN KEY (`sid`) REFERENCES `s01` (`id`)

5.3 使用规则(背下来)

操作顺序
建表先主表,后从表
插入先主表数据,后从表数据
删除数据先从表,后主表
删除表先从表,后主表
修改改完后仍要满足外键关系
查询不受限制

5.4 实验:先插从表会失败

-- 错误:主表还没有 id=1
insert into c01 values(100,1,'语文');
ERROR 1452 ... Cannot add or update a child row: a foreign key constraint fails ...
insert into s01 values(1,'张三');
insert into c01 values(100,1,'语文');  -- cname 是课程名示例
select * from s01;
select * from c01;

5.5 实验:删/改主表被挡住

-- 失败:从表还有引用 id=1
update s01 set id=2 where id=1;
delete from s01 where id=1;
ERROR 1451 ... Cannot delete or update a parent row ...

正确顺序:

delete from c01 where sid=1;
delete from s01 where id=1;

5.6 实验:先 drop 主表会失败

drop table s01;
ERROR 3730 ... Cannot drop table 's01' referenced by a foreign key ...
drop table c01;
drop table s01;

了解:生产里有人选择「不用数据库外键、在应用层校验」以降低耦合;考试与课堂常仍要求会建、会按顺序增删。入门先把规则记牢。

6. 完整跟练脚本

use train;

drop table if exists person;
create table person(
    id int primary key,
    name varchar(10) not null,
    sex varchar(1) default '女',
    age int check(age>=18),
    phone varchar(11) unique
);
desc person;
show create table person;

insert into person values(1,'张三','男',20,'13112345678');
insert into person(id,name,age,phone) values(2,'李四',19,'13212345678');
insert into person(id,name,age,phone) values(3,'王五',22,'13312345678');
select * from person;

-- 约束失败示例(注释可取消再执行观察报错)
-- insert into person values(1,'重复主键','男',20,'13911112222');
-- insert into person(id,name,age,phone) values(9,'未成年',17,'13922223333');
-- insert into person(id,name,age,phone) values(8,'李四',20,'13212345678');

drop table if exists auto01;
create table auto01(id int primary key auto_increment, name varchar(10));
insert into auto01(name) values('a'),('b');
select * from auto01;

drop table if exists c01;
drop table if exists s01;
create table s01(id int primary key, name varchar(10));
create table c01(
    cid int,
    sid int,
    cname varchar(10),
    constraint s01_id_c01_sid foreign key(sid) references s01(id)
);
insert into s01 values(1,'张三');
insert into c01 values(100,1,'语文');
select * from s01;
select * from c01;
-- delete from s01 where id=1;  -- 会 1451
delete from c01 where sid=1;
delete from s01 where id=1;
drop table if exists c01;
drop table if exists s01;

7. 速查表

目标写法
主键id int primary key
非空name varchar(10) not null
默认值sex varchar(1) default '女'
检查age int check(age>=18)
唯一phone varchar(11) unique
自增id int primary key auto_increment
看结构desc 表; / show create table 表;
外键(从表)constraint 名 foreign key(列) references 主表(主表列)
建/插/删顺序先主后从;删数据与删表先从后主

8. 今天的练习清单

  • 创建 person,用 desc / show create table 找出各约束
  • 主键:NULL、重复 id 各测一次
  • not null:name=null
  • default:全列 null vs 指定列省略 sex
  • check:age=15 失败,age=18 成功
  • unique:重复 phone
  • auto_increment 插入几行并观察 id
  • 外键:错误插入顺序 → 正确顺序 → 1451/3730 → 先从后主删除

常见错误

易错:以为 insert values(..., null, ...) 会自动变成 default——全列插入写 null 往往就是 null。
易错:主键与 unique 混淆:主键 = 非空 + 唯一;unique 主要强调唯一。
易错:外键列不在从表,或主表被引用列不是主键。
易错:先建从表、先删主表,导致报错。
易错:只 desc 找 check,看不到就以为没约束——用 show create table。
易错:业务号依赖 auto_increment 保证「连续、可预测」。

小结

  1. 约束是数据库层的数据规矩:主键、唯一、非空、check、default、外键。
  2. 验证约束最快的方式:故意插错数据,读报错码。
  3. 默认值:指定列插入、不写该列,才最稳。
  4. 外键:先主后从建表与插入;删除则相反。
  5. 下一篇 备份与实用命令:mysqldump 等运维向内容。

系列导航:总目录 · 上一篇:多表关联查询 · 下一篇:备份与实用命令

相关阅读

全部文章 →
← 返回列表更多「MySQL」