MySQL表的约束

表的约束

表中一定要有各种约束,通过约束,让我们未来插入数据库表中的数据是符合预期的。

有了约束插入的数据就有了条件,为了保证数据的可预期性。

1.空属性

  • 两个值:null(默认的)和not null(不为空)
  • 数据库默认字段基本都是字段为空,但是实际开发时,尽可能保证字段不为空,因为数据为空没法参与运算。
sql 复制代码
create table if not exists myclass(
    -> class_name varchar(20) not null,
    -> class_room varchar(20) not null,
    -> other varchar(20)
    -> );

class_name和class_room不能为空,插入时需要有数据

2.默认值

sql 复制代码
create table if not exists t1(
    -> name varchar(20) not null,
    -> age tinyint unsigned default 18,
    -> gender char(1) default '男'
    -> );
  • 不插入时使用默认值
  • 如果我们没有明确指定一列要插入,用的时default,如果建表中,对应列默认没有设置default值,无法直接插入。
  • 写了就被NULL约束,不写就被default约束,default默认值是NULL

3. comment注释

没有实际含义,专门用来描述字段

4.zerofill(补零)

int(10)unsigned 加上zerofill不够的位数补0,没有zerofill就只显示有的位数

有符号int是int(11)有11位

5.主键

主键:primary key用来唯一的约束字段里面的数据,不能重复,不能为空,一张表中最多只能有一个主键,主键所在的列通常是整数类型。

一个主键可以被添加到一列,也可以添加到多列上:复合主键

sql 复制代码
create table if not exists test_key(
    -> id int unsigned primary key comment '这个是学生的学号',
    -> name varchar(20) not null
    -> );

插入的id具有唯一性,相同的id不能插入进来

sql 复制代码
alter table 表名 drop primary key;    #删掉主键
alter table 表名 add primary key(id);    #添加主键
delete from test_key where name='孙权';    #删除

复合主键

sql 复制代码
create table pick_course(
    -> id int unsigned,
    -> course_id int unsigned comment '课程编号',
    -> score tinyint unsigned comment '这个学生课程考的分数',
    -> primary key(id,course_id)
    -> );
    desc pick_course;
+-----------+---------------------+------+-----+---------+-------+
| Field     | Type                | Null | Key | Default | Extra |
+-----------+---------------------+------+-----+---------+-------+
| id        | int(10) unsigned    | NO   | PRI | NULL    |       |
| course_id | int(10) unsigned    | NO   | PRI | NULL    |       |
| score     | tinyint(3) unsigned | YES  |     | NULL    |       |
+-----------+---------------------+------+-----+---------+-------+

id和course_id合起来是一个主键

自增长auto_increment

sql 复制代码
create table if not exists tt21(
    -> id int unsigned primary key auto_increment,
    -> name varchar(20) not null
    -> );
  • 自增长只能有一个
  • 任何一个字段要做自增长,前提是本身是一个索引(key一栏有值)

6.唯一键unique

唯一键可以为NULL,主键不能有两个重复的NULL

唯一键弥补了主键的不足:主键只能让一列或者多列不能重复

唯一键可以让多列保持唯一性。

sql 复制代码
create table student (
    -> id char(20) primary key,
    -> name varchar(32) not null,
    -> telphone char(20) unique key,
    -> qq varchar(64) unique key
    -> );
desc student;
+----------+-------------+------+-----+---------+-------+
| Field    | Type        | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| id       | char(20)    | NO   | PRI | NULL    |       |
| name     | varchar(32) | NO   |     | NULL    |       |
| telphone | char(20)    | YES  | UNI | NULL    |       |
| qq       | varchar(64) | YES  | UNI | NULL    |       |
+----------+-------------+------+-----+---------+-------+

一般而言,我们建议将主键设计成为和当前业务无关的字段,这样,当业务调整的时候,我们可以尽量不会对主键做过大的调整。

7.外键

外键用于定义主表和从表之间的关系:外键约束主要定义在从表上,主表则必须是有主键约束或者unique约束。当定义外键后,要求外键列数据必须在主表的主键列存在或者为null。

语法

foreign key (字段名) references 主表(列)

初识"外键"

主表class

sql 复制代码
create table if not exists class(
    -> id int unsigned primary key auto_increment,
    -> name varchar(20) not null
    -> );
mysql> select * from class;
+----+---------------+
| id | name          |
+----+---------------+
|  1 | 计科2601班    |
|  2 | 计科2602班    |
+----+---------------+

从表student

sql 复制代码
create table if not exists student(
    -> id int unsigned primary key auto_increment,
    -> name varchar(20) not null,
    -> telphone varchar(32) unique key,
    -> class_id int unsigned,
    -> foreign key(class_id) references class(id)
    -> );
mysql> desc student;
+----------+------------------+------+-----+---------+----------------+
| Field    | Type             | Null | Key | Default | Extra          |
+----------+------------------+------+-----+---------+----------------+
| id       | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| name     | varchar(20)      | NO   |     | NULL    |                |
| telphone | varchar(32)      | YES  | UNI | NULL    |                |
| class_id | int(10) unsigned | YES  | MUL | NULL    |                |
+----------+------------------+------+-----+---------+----------------+

在 MySQL 中,外键要求数据类型、长度、有无符号、字符集(若是字符串)必须完全一致。int 和 int unsigned 被视为不同类型,因此约束失败。

如何为已建的表添加外键

在 MySQL 中,可以使用 ALTER TABLE 语句为已创建的表添加外键。

1. 基本语法

最常用的完整语法如下:

sql 复制代码
ALTER TABLE 子表名
ADD CONSTRAINT 外键名
FOREIGN KEY (子表外键列名) REFERENCES 主表名(主表列名)
[ON DELETE 动作]
[ON UPDATE 动作];

2. 详细示例

假设我们有两张表:customers(客户表)是主表,orders(订单表)是子表。我们要让 orders 表中的 customer_id 字段引用 customers 表中的 id 字段。

sql 复制代码
-- 1. 创建主表 customers
CREATE TABLE customers (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100)
) ENGINE=InnoDB;

-- 2. 创建子表 orders (暂时没有外键)
CREATE TABLE orders (
    id INT PRIMARY KEY AUTO_INCREMENT,
    order_date DATE,
    customer_id INT
) ENGINE=InnoDB;

-- 3. 为已存在的 orders 表添加外键
ALTER TABLE orders
ADD CONSTRAINT fk_orders_customers   -- 指定一个有意义的外键名
FOREIGN KEY (customer_id)            -- 子表中的外键列
REFERENCES customers(id);            -- 主表及其被引用的列

添加成功后,orders 表的 customer_id 列的值必须存在于 customers 表的 id 列中。

3. 重要注意事项

在执行添加操作前,请确认以下几点,否则操作会失败:

  1. 存储引擎 :表和必须 使用 InnoDB 存储引擎,MySQL 的其他引擎(如 MyISAM)不支持外键。
  2. 字段类型匹配 :外键字段与主表被引用的字段,其数据类型和长度必须完全一致
  3. 主表有索引 :被引用的主表字段必须 有主键或唯一键(UNIQUE)约束。
  4. 数据一致性 :子表外键列中已有的数据,必须在主表被引用列中存在,否则无法添加外键。
  5. 约束命名 :建议使用 CONSTRAINT 外键名 来明确命名,方便后续管理。

4. 级联操作(ON DELETE / ON UPDATE

你可以通过 ON DELETEON UPDATE 子句,定义当主表数据被删除或更新时,子表如何自动响应。

  • CASCADE:主表数据删除/更新时,子表相关数据也自动删除/更新。
  • SET NULL :主表数据删除/更新时,子表的外键列自动设为 NULL(该列需允许为空)。
  • RESTRICT:如果子表有相关数据,则禁止删除/更新主表数据(默认行为)。

示例:当删除一个客户时,自动删除其所有订单。

sql 复制代码
ALTER TABLE orders
ADD CONSTRAINT fk_orders_customers
FOREIGN KEY (customer_id) REFERENCES customers(id)
ON DELETE CASCADE;
相关推荐
北漂燕郊杨哥1 小时前
Win11 环境下 phpStudy 安装 Redis 最新版,并为 PHP 8.5.9(NTS)配置 redis 扩展
数据库·redis·php
AlfredZhao1 小时前
SQL JOIN 写法:把多表关联条件写清楚
sql
2603_9651481110 小时前
如何解析JSON数据?API返回的商品信息处理教程
开发语言·数据库·python·自动化·json·api
ltl10 小时前
RocksDB 经典故障排查:L0、compaction 与 write stall
数据库
xfhuangfu11 小时前
Oracle中建立到CDB和PDB的连接
数据库·oracle·rpc
小小龙学IT11 小时前
DuckDB 深度实战:用 C++ 在进程内跑一个「分析型数据库」
数据库·c++
NineData11 小时前
DTCC 2026 预告|NineData CEO& 创始人叶正盛:面向 AI Agent 的数据库 DevOps 与数据复制实践
数据库·人工智能·数据库开发·devops·ninedata·数据库技术·dtcc
J_bean12 小时前
MySQL 事务是否必须手动开启?
数据库·mysql·数据库事务·自动提交·手动提交
J_bean12 小时前
MySQL InnoDB 如何检测死锁、判定死锁、处理死锁
数据库·mysql·死锁·死锁检测·处理死锁·死锁判定