【MySQL-3】表的约束

目录

[1. 整体学习的思维导图](#1. 整体学习的思维导图)

[2. 非空约束](#2. 非空约束)

[3. default约束](#3. default约束)

[4. No Null和default约束](#4. No Null和default约束)

[5. 列描述 comment](#5. 列描述 comment)

[6. Zerofill](#6. Zerofill)

[7. 主键 primary key](#7. 主键 primary key)

复合主键

[8. 自增长 auto_increment](#8. 自增长 auto_increment)

[9. 唯一键](#9. 唯一键)

[10. 外键](#10. 外键)

[11. 实现综合案例](#11. 实现综合案例)


1. 整体学习的思维导图

2. 非空约束

正如该标题一样,这个约束作用于数据是否能为空值。

举例我们有一个Student表,表中含有:

  • 学生姓名name

  • 学生年龄age

  • 学生性别gender

sql 复制代码
mysql> create table if not exists Student( 
-> name varchar(10), 
-> age tinyint unsigned, 
-> gender char(1) );
Query OK, 0 rows affected (0.01 sec)

mysql> desc Student;
+--------+---------------------+------+-----+---------+-------+
| Field  | Type                | Null | Key | Default | Extra |
+--------+---------------------+------+-----+---------+-------+
| name   | varchar(10)         | YES  |     | NULL    |       |
| age    | tinyint(3) unsigned | YES  |     | NULL    |       |
| gender | char(1)             | YES  |     | NULL    |       |
+--------+---------------------+------+-----+---------+-------+

mysql> show create table Student\G;
*************************** 1. row ***************************
       Table: Student
Create Table: CREATE TABLE `Student` (
  `name` varchar(10) COLLATE utf8_bin DEFAULT NULL,
  `age` tinyint(3) unsigned DEFAULT NULL,
  `gender` char(1) COLLATE utf8_bin DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin

我们先进行测试插入:

  • 小明 18 男

  • Null 19 女

sql 复制代码
mysql> insert into Student(name, age, gender) values('小明', 18, '男');
Query OK, 1 row affected (0.00 sec)

mysql> insert into Student(name, age, gender) values(null, 19, '女');
Query OK, 1 row affected (0.00 sec)

mysql> select * from Student;
+--------+------+--------+
| name   | age  | gender |
+--------+------+--------+
| 小明   |   18 | 男     |
| NULL   |   19 | 女     |
+--------+------+--------+

我们可以看到,该表格在Null项是允许插入空的,这意味这我们可以不用填入姓名,但是为了表的统一性和规范性,我们要求某些项必须填入信息,这时候就需要使用非空约束了!

sql 复制代码
mysql> alter table Student modify name varchar(10) not null;
Query OK, 0 rows affected (0.01 sec)

mysql> desc Student;
+--------+---------------------+------+-----+---------+-------+
| Field  | Type                | Null | Key | Default | Extra |
+--------+---------------------+------+-----+---------+-------+
| name   | varchar(10)         | NO   |     | NULL    |       |
| age    | tinyint(3) unsigned | YES  |     | NULL    |       |
| gender | char(1)             | YES  |     | NULL    |       |
+--------+---------------------+------+-----+---------+-------+

我们再次测试插入:

  • 小明 18 男

  • Null 19 女

sql 复制代码
mysql> insert into Student(name, age, gender) values('小明', 18, '男');
Query OK, 1 row affected (0.00 sec)

mysql> insert into Student(name, age, gender) values(null, 19, '女');
ERROR 1048 (23000): Column 'name' cannot be null

mysql> select * from Student;
+--------+------+--------+
| name   | age  | gender |
+--------+------+--------+
| 小明   |   18 | 男     |
+--------+------+--------+

由此可见非空约束的作用是让表中某一个字段类型为必填项!

3. default约束

default约束是当我们没填任何信息时,表中的字段类型会根据之前设定好的default值进行使用!

sql 复制代码
mysql> create table tb10( name varchar(10) default '张三', age tinyint default 18 );
Query OK, 0 rows affected (0.01 sec)

mysql> desc tb10;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| name  | varchar(10) | YES  |     | 张三    |       |
| age   | tinyint(4)  | YES  |     | 18      |       |
+-------+-------------+------+-----+---------+-------+

插入空值后,表中的数据会根据是否有default值进行填写。

sql 复制代码
mysql> insert into tb10 values();
Query OK, 1 row affected (0.00 sec)

mysql> insert into tb10 values();
Query OK, 1 row affected (0.00 sec)
mysql> select * from tb10;
+--------+------+
| name   | age  |
+--------+------+
| 张三   |   18 |
| 张三   |   18 |
+--------+------+

4. No Null和default约束

那么我们给一个字段类型同时加上No NULL和default会发生怎样的情况呢?

  • 非空约束要求我们必须填入数据,default约束可以在我们没填入的字段数据使用默认值

  • 非空+default可以使我们在不选择填入该字段类型时使用默认数据!

sql 复制代码
mysql> create table tb11(
    -> name varchar(10) not null default '张三',
    -> age tinyint unsigned);
Query OK, 0 rows affected (0.01 sec)

mysql> desc tb11;
+-------+---------------------+------+-----+---------+-------+
| Field | Type                | Null | Key | Default | Extra |
+-------+---------------------+------+-----+---------+-------+
| name  | varchar(10)         | NO   |     | 张三    |       |
| age   | tinyint(3) unsigned | YES  |     | NULL    |       |
+-------+---------------------+------+-----+---------+-------+
sql 复制代码
mysql> insert into tb11(name, age) values(null, 18);
ERROR 1048 (23000): Column 'name' cannot be null
mysql> insert into tb11(age) values(18);
Query OK, 1 row affected (0.00 sec)

mysql> select * from tb11;
+--------+------+
| name   | age  |
+--------+------+
| 张三   |   18 |
+--------+------+

5. 列描述 comment

列描述:comment,没有实际含义,专门用来描述字段,会根据表创建语句保存,用来给程序员或DBA来进行了解。

sql 复制代码
mysql> create table student_from(
    -> name varchar(10) not null comment '学生的姓名',
    -> age tinyint unsigned comment '学生的年龄',
    -> id varchar(25) not null default '2023090640XXX' comment '学生的学号'
    -> );
    
mysql> show create table student_from\G;
*************************** 1. row ***************************
       Table: student_from
Create Table: CREATE TABLE `student_from` (
  `name` varchar(10) COLLATE utf8_bin NOT NULL COMMENT '学生的姓名',
  `age` tinyint(3) unsigned DEFAULT NULL COMMENT '学生的年龄',
  `id` varchar(25) COLLATE utf8_bin NOT NULL DEFAULT '2023090640XXX' COMMENT '学生的学号'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin
1 row in set (0.00 sec)

6. Zerofill

我们之前了解到跟在一个类型后面的数字都会表达一些特殊的含义,那么跟着int(num)的num真正的含义到底是什么呢,这就需要借助zerofill来观察了。

我们创建一个表,两个字段类型一个添加zerofill,一个不添加。

sql 复制代码
mysql> create table tb_int1(
    -> num1 int,
    -> num2 int zerofill
    -> );
Query OK, 0 rows affected (0.01 sec)

mysql> desc tb_int1;
+-------+---------------------------+------+-----+---------+-------+
| Field | Type                      | Null | Key | Default | Extra |
+-------+---------------------------+------+-----+---------+-------+
| num1  | int(11)                   | YES  |     | NULL    |       |
| num2  | int(10) unsigned zerofill | YES  |     | NULL    |       |
+-------+---------------------------+------+-----+---------+-------+

我们任意插入以下数据:

  • 10 10

  • 15 15

sql 复制代码
mysql> insert into tb_int1 values(10, 10);
Query OK, 1 row affected (0.01 sec)

mysql> insert into tb_int1 values(15, 15);
Query OK, 1 row affected (0.00 sec)

mysql> select * from tb_int1;
+------+------------+
| num1 | num2       |
+------+------------+
|   10 | 0000000010 |
|   15 | 0000000015 |
+------+------------+

这次可以看到a的值由原来的10变成0000000010,这就是zerofill属性的作用,如果宽度小于设定的宽度(这里设置的是10),自动填充0。要注意的是,这只是最后显示的结果,在MySQL中实际存储的还是1。为什么是这样呢?我们可以用hex函数来证明。

sql 复制代码
mysql> select num1, hex(num2) from tb_int1;
+------+-----------+
| num1 | hex(num2) |
+------+-----------+
|   10 | A         |
|   15 | F         |
+------+-----------+

可以看出数据库内部存储的还是1,00001只是设置了zerofill属性后的一种格式化输出而已。

7. 主键 primary key

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

sql 复制代码
mysql> create table tb12(
    -> id int unsigned primary key comment '学生的id',
    -> name varchar(10) default '未知' comment '学生的姓名'
    -> );
Query OK, 0 rows affected (0.01 sec)

mysql> desc tb12;
+-------+------------------+------+-----+---------+-------+
| Field | Type             | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+-------+
| id    | int(10) unsigned | NO   | PRI | NULL    |       |
| name  | varchar(10)      | YES  |     | 未知    |       |
+-------+------------------+------+-----+---------+-------+
sql 复制代码
mysql> insert into tb12(id, name) values(1, '欧阳');
Query OK, 1 row affected (0.00 sec)

mysql> insert into tb12(id, name) values(1, '牛马');
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'

复合主键

一个表中虽然只能有一个主键,但是一个主键却可以约束多个字段类型!

  • 追加主键
sql 复制代码
alter table 表名 add primary key(字段列表)  
  • 删除主键
sql 复制代码
alter table 表名 drop primary key;  
sql 复制代码
mysql> create table tb13(
    -> num1 int(1) primary key,
    -> num2 int(1)
    -> );
Query OK, 0 rows affected (0.01 sec)

mysql> insert into tb13(num1, num2) values(1, 2);
Query OK, 1 row affected (0.00 sec)
mysql> insert into tb13(num1, num2) values(2, 2);
Query OK, 1 row affected (0.00 sec)

mysql> alter table tb13 drop primary key;
Query OK, 2 rows affected (0.03 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> alter table tb13 add primary key (num1, num2);
Query OK, 0 rows affected (0.04 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc tb13;
+-------+--------+------+-----+---------+-------+
| Field | Type   | Null | Key | Default | Extra |
+-------+--------+------+-----+---------+-------+
| num1  | int(1) | NO   | PRI | NULL    |       |
| num2  | int(1) | NO   | PRI | NULL    |       |
+-------+--------+------+-----+---------+-------+

8. 自增长 auto_increment

我们平时注册qq时,输入完手机号和验证码,qq后端注册成功会给我们返回一个qq号,这个qq号就是自增长的产物,比如马总的qq10001,我的qq2331701342,根据注册用户的数量和注册时间分配qq号。

自增长的特点:

  • 任何一个字段要做自增长,前提是本身是一个索引(key一栏有值)

  • 自增长字段必须是整数

  • 一张表最多只能有一个自增长

sql 复制代码
mysql> create table tb14( 
-> id int unsigned primary key auto_increment, 
-> name varchar(20) not null );


mysql> desc tb14;
+-------+------------------+------+-----+---------+----------------+
| Field | Type             | Null | Key | Default | Extra          |
+-------+------------------+------+-----+---------+----------------+
| id    | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| name  | varchar(20)      | NO   |     | NULL    |                |
+-------+------------------+------+-----+---------+----------------+
sql 复制代码
mysql> insert into tb14(name) values('欧阳');
mysql> insert into tb14(name) values('牛马');
mysql> insert into tb14(name) values('张明东');
mysql> insert into tb14(name) values('鬼哥');

mysql> select * from tb14;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | 欧阳      |
|  2 | 牛马      |
|  3 | 张明东    |
|  4 | 鬼哥      |
+----+-----------+

我们可以看到id这一字段类型我们并没插入和干预,它自己增长。

假设我们自主干预插入 10 刘越,后面再次插入韩旭鹏/王星博那么他们的id号又从几号开始呢?

  • 是从5还是从11
sql 复制代码
mysql> insert into tb14(id,name) values(10, '刘越');
mysql> insert into tb14(name) values('韩旭鹏');
mysql> insert into tb14(name) values('王星博');

mysql> select * from tb14;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | 欧阳      |
|  2 | 牛马      |
|  3 | 张明东    |
|  4 | 鬼哥      |
| 10 | 刘越      |
| 11 | 韩旭鹏    |
| 12 | 王星博    |
+----+-----------+

在插入后获取上次插入的 AUTO_INCREMENT 的值(批量插入获取的是第一个值)

sql 复制代码
mysql > select last_insert_id();  

9. 唯一键

  • 一张表中有往往有很多字段需要唯一性,数据不能重复,但是一张表中只能有一个主键:唯一键就可以解决表中有多个字段需要唯一性约束的问题,一个表中可以存在多个唯一键。

  • 唯一键的本质和主键差不多,唯一键允许为空,而且可以多个为空,空字段不做唯一性比较。

关于唯一键和主键的区别:

我们可以简单理解成,主键更多的是标识表之间唯一性的。而唯一键更多的是保证在业务上一张表中不同字段,不要和别的字段信息出现重复。

sql 复制代码
unique key
sql 复制代码
mysql> create table tb15(
    -> id int unsigned unique key,
    -> name varchar(10)
    -> );
Query OK, 0 rows affected (0.01 sec)

mysql> desc tb15;
+-------+------------------+------+-----+---------+-------+
| Field | Type             | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+-------+
| id    | int(10) unsigned | YES  | UNI | NULL    |       |
| name  | varchar(10)      | YES  |     | NULL    |       |
+-------+------------------+------+-----+---------+-------+
mysql> insert into tb15(id,name) values(1, '欧阳');
Query OK, 1 row affected (0.00 sec)

mysql> insert into tb15(id,name) values(1, '牛马');
ERROR 1062 (23000): Duplicate entry '1' for key 'id'    -- id唯一

mysql> insert into tb15(id,name) values(NULL, '牛马');
Query OK, 1 row affected (0.00 sec)                     -- 但是插入的id可以为NULL

mysql> select * from tb15;
+------+--------+
| id   | name   |
+------+--------+
|    1 | 欧阳   |
| NULL | 牛马   |
+------+--------+

10. 外键

如果我们现在有两张表,一个学生表记录了学生的name,age,telphone,class_id,另外一张class表记录了学生的班级id,和班级名称。我们需要将这两张表的class_id和id关联起来,表面上我们可以通过插入时的判断进行关联,但是插入错误的也不会报错,这时候就需要约束进行强制管理了,这就是外键。

sql 复制代码
foreign key (字段名) references 主表(列)  
  • 外键用于定义主表和从表之间的关系:外键约束主要定义在从表上,主表则必须是有主键约束或unique约束。当定义外键后,要求外键列数据必须在主表的主键列存在或为null。
sql 复制代码
mysql> create table class(
    -> id varchar(10) primary key,
    -> class_name varchar(10) not null comment '班级名称'
    -> );

mysql> create table stu( 
    -> class_id varchar(10), 
    -> name varchar(20) not null comment '学生姓名', 
    -> age tinyint default 18, telphone varchar(15), 
    -> foreign key(class_id) references class(id));

mysql> desc class;
+------------+-------------+------+-----+---------+-------+
| Field      | Type        | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| id         | varchar(10) | NO   | PRI | NULL    |       |
| class_name | varchar(10) | NO   |     | NULL    |       |
+------------+-------------+------+-----+---------+-------+

mysql> desc stu;
+----------+-------------+------+-----+---------+-------+
| Field    | Type        | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| class_id | varchar(10) | YES  | MUL | NULL    |       |
| name     | varchar(20) | NO   |     | NULL    |       |
| age      | tinyint(4)  | YES  |     | 18      |       |
| telphone | varchar(15) | YES  |     | NULL    |       |
+----------+-------------+------+-----+---------+-------+

mysql> insert into class(id, class_name) values(1, '软件工程001');
mysql> insert into class(id, class_name) values(2, '软件工程002');

mysql> select * from class;
+----+-----------------+
| id | class_name      |
+----+-----------------+
| 1  | 软件工程001     |
| 2  | 软件工程002     |
+----+-----------------+

mysql> insert into stu values(1, '欧阳', 18, '123456789');
mysql> insert into stu values(1, '牛马', 19, '123456780');
mysql> insert into stu values(2, '张明东', 20, '123456781');
Query OK, 1 row affected (0.00 sec)

mysql> insert into stu values(3, '卢智博', 8, '183456781');
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`Class`.`stu`, CONSTRAINT `stu_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `class` (`id`))
-- 由于id和class_id的外键约束,并没有3

mysql> select * from stu;
+----------+-----------+------+-----------+
| class_id | name      | age  | telphone  |
+----------+-----------+------+-----------+
| 1        | 欧阳      |   18 | 123456789 |
| 1        | 牛马      |   19 | 123456780 |
| 2        | 张明东    |   20 | 123456781 |
+----------+-----------+------+-----------+

11. 实现综合案例

有一个商店的数据,记录客户及购物情况,有以下三个表组成:

  • 商品goods(商品编号goods_id,商品名goods_name, 单价unitprice, 商品类别category, 供应商provider)

  • 客户customer(客户号customer_id,姓名name,住址address,邮箱email,性别sex,身份证card_id)

  • 购买purchase(购买订单号order_id,客户号customer_id,商品号goods_id,购买数量nums)

    • 要求:

      • 每个表的主外键

      • 客户的姓名不能为空值邮箱不能重复

      • 客户的性别(男,女)

sql 复制代码
mysql> create table if not exists goods(
    -> goods_id int unsigned not null unique auto_increment comment '商品编号',
    -> goods_name varchar(30) comment '商品名',
    -> unitprice float(10,2) comment '单价',
    -> category varchar(25) comment '商品类别',
    -> provider varchar(30) comment '供应商'
    -> );


mysql> desc goods;
+------------+------------------+------+-----+---------+----------------+
| Field      | Type             | Null | Key | Default | Extra          |
+------------+------------------+------+-----+---------+----------------+
| goods_id   | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| goods_name | varchar(30)      | YES  |     | NULL    |                |
| unitprice  | float(10,2)      | YES  |     | NULL    |                |
| category   | varchar(25)      | YES  |     | NULL    |                |
| provider   | varchar(30)      | YES  |     | NULL    |                |
+------------+------------------+------+-----+---------+----------------+


mysql> create table if not exists customer(
    -> customer_id int unsigned primary key auto_increment comment '客户号',
    -> name varchar(30) not null comment '姓名',
    -> address varchar(30) comment '住址',
    -> email varchar(25) unique comment '邮箱',
    -> sex enum('男', '女') comment '性别',
    -> card_id varchar(30) unique comment '身份证'
    -> );


mysql> desc customer;
+-------------+-------------------+------+-----+---------+----------------+
| Field       | Type              | Null | Key | Default | Extra          |
+-------------+-------------------+------+-----+---------+----------------+
| customer_id | int(10) unsigned  | NO   | PRI | NULL    | auto_increment |
| name        | varchar(30)       | NO   |     | NULL    |                |
| address     | varchar(30)       | YES  |     | NULL    |                |
| email       | varchar(25)       | YES  | UNI | NULL    |                |
| sex         | enum('男','女')   | YES  |     | NULL    |                |
| card_id     | varchar(30)       | YES  | UNI | NULL    |                |
+-------------+-------------------+------+-----+---------+----------------+


create table purchase( 
    -> order_id int unsigned not null unique key, 
    -> customer_id varchar(5), 
    -> goods_id varchar(5), 
    -> nums int unsigned default 0 , 
    -> foreign key(customer_id) references customer(customer_id), 
    -> foreign key(goods_id) references goods(goods_id)
);

mysql> desc purchase;
+-------------+------------------+------+-----+---------+----------------+
| Field       | Type             | Null | Key | Default | Extra          |
+-------------+------------------+------+-----+---------+----------------+
| order_id    | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| customer_id | varchar(5)       | YES  |     | NULL    |                |
| goods_id    | varchar(5)       | YES  |     | NULL    |                |
| nums        | int(10) unsigned | YES  |     | 0       |                |
+-------------+------------------+------+-----+---------+----------------+
相关推荐
云和数据.ChenGuang1 小时前
Django 应用安装脚本 – 如何将应用添加到 INSTALLED_APPS 设置中 原创
数据库·django·sqlite
woshilys1 小时前
sql server 查询对象的修改时间
运维·数据库·sqlserver
Hacker_LaoYi1 小时前
SQL注入的那些面试题总结
数据库·sql
建投数据2 小时前
建投数据与腾讯云数据库TDSQL完成产品兼容性互认证
数据库·腾讯云
Hacker_LaoYi3 小时前
【渗透技术总结】SQL手工注入总结
数据库·sql
岁月变迁呀3 小时前
Redis梳理
数据库·redis·缓存
独行soc3 小时前
#渗透测试#漏洞挖掘#红蓝攻防#护网#sql注入介绍06-基于子查询的SQL注入(Subquery-Based SQL Injection)
数据库·sql·安全·web安全·漏洞挖掘·hw
你的微笑,乱了夏天4 小时前
linux centos 7 安装 mongodb7
数据库·mongodb
工业甲酰苯胺4 小时前
分布式系统架构:服务容错
数据库·架构
拭心5 小时前
Google 提供的 Android 端上大模型组件:MediaPipe LLM 介绍
android