目录
[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 | |
+-------------+------------------+------+-----+---------+----------------+