目录
一、约束的意义
二、非空约束和缺省值约束
1、非空约束
2、缺省值约束
3、缺省值和空值的关系
三、列描述
四、zerofill
1、创建有符号int和无符号int圆括号数字的区别
2、zerofill的作用
五、主键约束
1、创建带有主键的表
2、主键列不允许重复
3、利用主键约束查询或修改指定列的信息
4、让一个表丢弃主键约束
5、让一个无主键约束的表增加主键约束
6、复合主键
六、自增长
1、创建带有自增长字段的表
2、连续插入,发现id自增长
3、创建表时可以自定义自增长起始值
4、last_insert_id()函数获取最后一次自增长的值
七、唯一键约束
1、创建带有唯一键的表
2、创建带有主键和唯一键的表
3、可以将唯一键加上非空约束
八、外键约束
1、创建班级表和学生表
2、建立班级表id(主表)与学生表class_id(从表)的外键约束
3、向含有外键约束的学生表中插入数据
4、删除班级表id=2的字段
九、综合案例
表中有很多字段,例如性别这一列,正常人会填“男”或“女”,总会有人填错或瞎填,就会导致数据紊乱,通过约束,倒逼程序员插入数据库表中的数据符合预期。
两个值:null(默认的)和not null(不为空)
MySQL中的NULL代表什么都没有。
MySQL中的''代表空串。
#创建带有非空属性的表
mysql> create table if not exists myclass(
-> class_name varchar(20) not null,
-> class_room varchar(20) not null,
-> other varchar(20)
-> );
Query OK, 0 rows affected (0.28 sec)
#在非空属性的表中插入数据将失败
mysql> insert into myclass (class_name,class_room) values ('二班',NULL);
ERROR 1048 (23000): Column 'class_room' cannot be null
#创建带有缺省值和非空值的表t12
mysql> create table if not exists t12(
-> name varchar(20) not null,
-> age tinyint unsigned default 18,
-> gender char(1) default '男'
-> );
Query OK, 0 rows affected (0.27 sec)
#可以看到相关字段出现缺省值
mysql> desc t12;
+--------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------------------+------+-----+---------+-------+
| name | varchar(20) | NO | | NULL | |
| age | tinyint(3) unsigned | YES | | 18 | |
| gender | char(1) | YES | | 男 | |
+--------+---------------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
#创建非空约束并带有缺省值的表t13
mysql> create table t13(
-> name varchar(20) not null,
-> age tinyint default 18,
-> gender char(1) not null default '男'
-> );
Query OK, 0 rows affected (0.27 sec)
mysql> desc t13;
+--------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| name | varchar(20) | NO | | NULL | |
| age | tinyint(4) | YES | | 18 | |
| gender | char(1) | NO | | 男 | |
+--------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
试着向表中进行插入:
#插入失败,name字段有空值约束
mysql> insert into t13 (name,age) values (NULL,19);
ERROR 1048 (23000): Column 'name' cannot be null
#插入失败,name字段没有缺省值
mysql> insert into t13 (age) values (19);
ERROR 1364 (HY000): Field 'name' doesn't have a default value
#插入成功,其中gender字段使用了缺省值
mysql> insert into t13 (name,age) values ('张三',19);
Query OK, 1 row affected (0.03 sec)
mysql> select* from t13;
+--------+------+--------+
| name | age | gender |
+--------+------+--------+
| 张三 | 19 | 男 |
+--------+------+--------+
1 row in set (0.00 sec)
结论:
1、如果用户没有明确指定某一列要进行插入,将判断是否存在default,如果在创建表时该列没有设置default,插入数据将报错。
2、如果用户对某列进行插入,将判断某列是null还是not null,如果用户没有对not null的列插入数据时,插入数据将报错。
3、如果我们在创建表的时候没有对字段设置为not null,也没有设置为default,那么该字段默认default null。
4、not null和defalut一般不需要同时出现,因为default本身有默认值,不会为空
列描述:comment,没有实际含义,专门用来描述字段,会根据表创建语句保存,用来给程序员或DBA来进行了解。
创建带有列描述的表:
#创建带有列描述的表,没有实际含义
mysql> create table i not exists t14(
-> name varchar(20) not null comment '这是用户名',
-> age tinyint default 18 comment '这是用户年龄',
-> gender char(1) default '男' comment '这个是用户性别'
-> );
Query OK, 0 rows affected (0.19 sec)
mysql> show create table t14\G;
*************************** 1. row ***************************
Table: t14
Create Table: CREATE TABLE `t14` (
`name` varchar(20) NOT NULL COMMENT '这是用户名',
`age` tinyint(4) DEFAULT '18' COMMENT '这是用户年龄',
`gender` char(1) DEFAULT '男' COMMENT '这个是用户性别'
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
mysql> create table if not exists t16(
-> a int not null,
-> b int unsigned not null
-> );
Query OK, 0 rows affected (0.22 sec)
mysql> desc t16;
+-------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+-------+
| a | int(11) | NO | | NULL | |
| b | int(10) unsigned | NO | | NULL | |
+-------+------------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
有符号int圆括号中的数字为11,无符号int圆括号中的数字为10。这是因为有符号int其中一位是符号位。
创建一个int unsigned类型的字段,MySQL会自动将类型修改为int(10),这个代表什么意思呢?如果没有zerofill这个属性,那么括号内的数字是毫无意义的。
创建带有zerofill约束的表t15:
#创建带有zerofill约束的表t15
mysql> create table if not exists t15(
-> a int unsigned not null,
-> b int unsigned zerofill not null
-> );
Query OK, 0 rows affected (0.18 sec)
#查看表的结构信息,发现MySQL在创建表时自动给int加上了(10)
mysql> desc t15;
+-------+---------------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------------+------+-----+---------+-------+
| a | int(10) unsigned | NO | | NULL | |
| b | int(10) unsigned zerofill | NO | | NULL | |
+-------+---------------------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
#在表中插入数据
mysql> insert into t15 (a,b) values (100,200);
Query OK, 1 row affected (0.03 sec)
#打印表发现b列空位用0补齐
mysql> select* from t15;
+-----+------------+
| a | b |
+-----+------------+
| 100 | 0000000200 |
+-----+------------+
1 row in set (0.01 sec)
打印表发现b列空位用0补齐。zerofill的存在,就能让某列数据的高位用0补齐。例如int(4),输入11,存储0011,输入11111,存储11111,对存储的数字不影响,位数不够的话就在高位补0:
mysql> alter table t15 modify b int(4) unsigned zerofill not null;
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> insert into t15 (a,b) values (2,1);
Query OK, 1 row affected (0.06 sec)
mysql> insert into t15 (a,b) values (2,11);
Query OK, 1 row affected (0.04 sec)
mysql> insert into t15 (a,b) values (2,111);
Query OK, 1 row affected (0.04 sec)
mysql> insert into t15 (a,b) values (2,1111);
Query OK, 1 row affected (0.04 sec)
mysql> insert into t15 (a,b) values (2,11111);
Query OK, 1 row affected (0.04 sec)
mysql> select * from t15;
+-----+-------+
| a | b |
+-----+-------+
| 100 | 0200 |
| 2 | 0001 |
| 2 | 0011 |
| 2 | 0111 |
| 2 | 1111 |
| 2 | 11111 |
+-----+-------+
6 rows in set (0.02 sec)
那么这东西有啥用呢?比如现在有200个班级,编号从001-200开始,那么创建表时将字段设置为int(3) unsigned或者int(4)就行了。
主键(primary key):用来唯一的约束该字段里面的数据,不能重复,不能为空,一张表中最多只能有一个主键;主键所在的列通常是整数类型。例如学校中的学号,具有唯一性。
mysql> insert into test_key values (1,'张三');
Query OK, 1 row affected (0.04 sec)
mysql> insert into test_key values (1,'李四');
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
将id值设置为主键,在插入数据时,主键列不允许插入相同的值。
利用主键约束查找信息:
#利用主键约束查找信息
mysql> select* from test_key where id=1;
+----+--------+
| id | name |
+----+--------+
| 1 | 张三 |
+----+--------+
1 row in set (0.01 sec)
利用主键约束更新信息:
#利用主键约束更新信息
mysql> update test_key set name='赵四' where id=1;
Query OK, 1 row affected (0.03 sec)
#1号id由张三修改为赵四
mysql> select* from test_key where id=1;
+----+--------+
| id | name |
+----+--------+
| 1 | 赵四 |
+----+--------+
1 row in set (0.00 sec)
mysql> alter table test_key drop primary key;
Query OK, 1 row affected (0.52 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> desc test_key;
+-------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+-------+
| id | int(10) unsigned | NO | | NULL | |
| name | varchar(20) | NO | | NULL | |
+-------+------------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql> alter table test_key add primary key(id);
Query OK, 0 rows affected (0.47 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc test_key;
+-------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+-------+
| id | int(10) unsigned | NO | PRI | NULL | |
| name | varchar(20) | NO | | NULL | |
+-------+------------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
在创建表的时候,在所有字段之后,使用primary key(主键字段列表)来创建主键,如果有多个字段作为主键,可以使用复合主键。
以下是学生id和课程id共同组成的复合主键:
#学生id和课程id共同组成的复合主键的表
mysql> create table pick_course(
-> id int unsigned,
-> course_id int unsigned comment '课程编号',
-> score tinyint unsigned comment '该学生的考试分数',
-> primary key(id,course_id)
-> );
Query OK, 0 rows affected (0.39 sec)
#查看表的结构信息,发现主键由id和course_id构成
mysql> 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 | |
+-----------+---------------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
对含有复合主键的表中插入数据:
#1号学生选了20号课,OK
mysql> insert into pick_course values (1,20,90);
Query OK, 1 row affected (0.03 sec)
#1号学生选了21号课,OK
mysql> insert into pick_course values (1,21,90);
Query OK, 1 row affected (0.03 sec)
#2号学生选了20号课,OK
mysql> insert into pick_course values (2,20,90);
Query OK, 1 row affected (0.04 sec)
#1号学生选了20号课,插入失败,因为主键重复
mysql> insert into pick_course values (1,21,50);
ERROR 1062 (23000): Duplicate entry '1-21' for key 'PRIMARY'
复合主键本质就是多个字段合为一个主键,这些合并的字段全部重复了,才算主键重复。
auto_increment:每次插入新数据的时候,被设置为自增长的字段的值每次会+1。通常和主键搭配使用,作为逻辑主键。
自增长的特点:
1、任何一个字段要做自增长,前提是本身是一个索引(key一栏有值)
2、自增长字段必须是整数
3、一张表最多只能有一个自增长
#创建带有自增长字段的表t17
mysql> create table if not exists t17(
-> id int unsigned primary key auto_increment,
-> name varchar(20) not null
-> );
Query OK, 0 rows affected (0.29 sec)
#打印表t17的结构,额外栏出现auto_increment字样
mysql> desc t17;
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(20) | NO | | NULL | |
+-------+------------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)
#连续插入
mysql> insert into t17 (name) values ('a');
Query OK, 1 row affected (0.05 sec)
mysql> insert into t17 (name) values ('b');
Query OK, 1 row affected (0.03 sec)
mysql> insert into t17 (name) values ('c');
Query OK, 1 row affected (0.03 sec)
#id从1开始进行自增长
mysql> select* from t17;
+----+------+
| id | name |
+----+------+
| 1 | a |
| 2 | b |
| 3 | c |
+----+------+
3 rows in set (0.01 sec)
id会从1开始,进行自增长。此时,如果程序员手动将下一个插入的名字的id调整为1000,那么后续的自增长将从1001开始。
#创建表,并将自增长值初始值设置为500
mysql> create table if not exists t18(
-> id int unsigned primary key auto_increment,
-> name varchar(20) not null
-> )auto_increment=500;
Query OK, 0 rows affected (0.18 sec)
#打印创建表的细节
mysql> show create table t18\G;
*************************** 1. row ***************************
Table: t18
Create Table: CREATE TABLE `t18` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=500 DEFAULT CHARSET=utf8
1 row in set (0.01 sec)
mysql> select last_insert_id();
+------------------+
| last_insert_id() |
+------------------+
| 3 |
+------------------+
1 row in set (0.01 sec)
最后一次自增长的值是3,下一次自增长的值是4。
一张表中有往往有很多字段需要唯一性,数据不能重复,但是一张表中只能有一个主键:唯一键就可以解决表中有多个字段需要唯一性约束的问题。一张表中主键只能有一个,但是唯一键可以有多个。
唯一键的本质和主键差不多,唯一键允许为空,而且可以有多个null,空字段不做唯一性比较。
关于唯一键和主键的区别:
侧重点不一样。主键更多的是标识唯一性的,例如id等与业务逻辑无关的字段。
唯一键更多的是保证在业务上,保证业务字段不要和别的信息出现重复。
例如:可以将学生id设置为主键,学生电话、QQ等设置为唯一键。
#创建带有唯一键的表
mysql> create table if not exists stu(
-> id char(20) unique comment '这是一个学生的唯一键',
-> name varchar(32) not null
-> );
Query OK, 0 rows affected (0.26 sec)
#插入数据成功,id:12345,姓名:张三
mysql> insert into stu (id,name) values ('12345','张三');
Query OK, 1 row affected (0.03 sec)
#和主键一样,插入相同的唯一键会失败
mysql> insert into stu (id,name) values ('12345','李四');
ERROR 1062 (23000): Duplicate entry '12345' for key 'id'
#多次插入唯一键是null的数据,成功。唯一键可以有多个空
mysql> insert into stu (id,name) values (null,'李四');
Query OK, 1 row affected (0.02 sec)
mysql> insert into stu (id,name) values (null,'李四');
Query OK, 1 row affected (0.04 sec)
mysql> insert into stu (id,name) values (null,'李四');
唯一键和主键一样,不能重复。但是可以有多个null。
#创建带有主键和唯一键的表
mysql> create table if not exists student(
-> id char(20) primary key,
-> name varchar(32) not null,
-> telphone char(20) unique key,
-> qq varchar(64) unique key
-> );
Query OK, 0 rows affected (0.27 sec)
#打印表的结构
mysql> 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 | |
+----------+-------------+------+-----+---------+-------+
4 rows in set (0.01 sec)
#为唯一键加上非空约束
mysql> alter table student modify qq char(20) unique not null;
Query OK, 0 rows affected, 1 warning (0.68 sec)
Records: 0 Duplicates: 0 Warnings: 1
唯一键加上非空约束后,就和主键的作用一样了。但是记住,他们俩的侧重点不同,主键修饰非业务字段,而唯一键修饰业务字段,均保证字段的唯一性。
外键用于定义主表和从表之间的关系:外键约束主要定义在从表上,主表则必须是有主键约束或unique约束。当定义外键后,要求外键列数据必须在主表的主键列存在或为null。
#创建班级表
mysql> create table if not exists class(
-> id int primary key,
-> name varchar(32) not null
-> );
Query OK, 0 rows affected (0.20 sec)
#创建学生表
mysql> create table if not exists student(
-> id int unsigned primary key auto_increment,
-> name varchar(20) not null,
-> telphone varchar(32) not null,
-> class_id int
-> );
Query OK, 0 rows affected (0.28 sec)
#在班级表中新增班级信息
mysql> insert into class values (1,'一班');
Query OK, 1 row affected (0.04 sec)
mysql> insert into class values (2,'二班');
Query OK, 1 row affected (0.03 sec)
#在学生表中新增学生信息
mysql> insert into student (name,telphone,class_id) values ('张三','123456',1);
Query OK, 1 row affected (0.05 sec)
mysql> insert into student (name,telphone,class_id) values ('李四','222222',1);
Query OK, 1 row affected (0.05 sec)
mysql> insert into student (name,telphone,class_id) values ('王五','333333',2);
Query OK, 1 row affected (0.04 sec)
如果此时删除一班的信息或者有个学生的class_id信息出现了不存在的三班,这是绝对不合理的。班级表的id和学生表的class_id其实构成关联关系,但是还缺少约束!
foreign key (从表字段名) references 主表(列)
删除上方的student表,重新建立一张带有外键约束的student表:
#从表与主表建立外键约束
mysql> create table if not exists student(
-> id int unsigned primary key,
-> name varchar(20) not null,
-> telephone varchar(32) unique key,
-> class_id int,
-> foreign key(class_id) references class(id)
-> );
Query OK, 0 rows affected (0.33 sec)
#查看student表结构,class_id存在外键约束
mysql> desc student;
+-----------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+------------------+------+-----+---------+-------+
| id | int(10) unsigned | NO | PRI | NULL | |
| name | varchar(20) | NO | | NULL | |
| telephone | varchar(32) | YES | UNI | NULL | |
| class_id | int(11) | YES | MUL | NULL | |
+-----------+------------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
上一节中,我们让学生表的class_id与班级表id建立外键约束,那么本章对学生表进行数据的插入:
#班级表id有1和2,我们在学生表中插入的class_id只要是1和2的都可以成功插入
mysql> insert into student (id,name,telephone,class_id) values (100,'张三','1234560',1);
Query OK, 1 row affected (0.04 sec)
mysql> insert into student (id,name,telephone,class_id) values (101,'李四','2222222',1);
Query OK, 1 row affected (0.06 sec)
mysql> insert into student (id,name,telephone,class_id) values (102,'王五','333333',2);
Query OK, 1 row affected (0.03 sec)
#在学生表中插入不存在的id:3,插入失败
mysql> insert into student (id,name,telephone,class_id) values (103,'赵六','444444',3);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test_db`.`student`, CONSTRAINT `student_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `class` (`id`))
#查看学生表的信息
mysql> select* from student;
+-----+--------+-----------+----------+
| id | name | telephone | class_id |
+-----+--------+-----------+----------+
| 100 | 张三 | 1234560 | 1 |
| 101 | 李四 | 2222222 | 1 |
| 102 | 王五 | 333333 | 2 |
+-----+--------+-----------+----------+
3 rows in set (0.00 sec)
建立外键的本质其实就是把相关性交给MySQL去审核了,提前告诉MySQL表之间的约束关系,那么当用户插入不符合业务逻辑的数据的时候,MySQL不允许你插入。
#尝试删除班级表中id为2的字段,删除失败
mysql> delete from class where id=2;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`test_db`.`student`, CONSTRAINT `student_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `class` (`id`))
尝试删除班级表中id为2的字段,因为学生表中王五对应的id是2,存在外键约束,所以删除失败。那么我们先把学生表中的王五这条数据删了:
#打印学生表的数据
mysql> select* from student;
+-----+--------+-----------+----------+
| id | name | telephone | class_id |
+-----+--------+-----------+----------+
| 100 | 张三 | 1234560 | 1 |
| 101 | 李四 | 2222222 | 1 |
| 102 | 王五 | 333333 | 2 |
+-----+--------+-----------+----------+
3 rows in set (0.00 sec)
#在学生表中删除王五的数据
mysql> delete from student where class_id=2;
Query OK, 1 row affected (0.04 sec)
#打印学生表的数据,王五的数据被删除
mysql> select* from student;
+-----+--------+-----------+----------+
| id | name | telephone | class_id |
+-----+--------+-----------+----------+
| 100 | 张三 | 1234560 | 1 |
| 101 | 李四 | 2222222 | 1 |
+-----+--------+-----------+----------+
2 rows in set (0.00 sec)
#学生表中已经没有字段和班级表id=2构成外键约束,删除成功
mysql> delete from class where id=2;
Query OK, 1 row affected (0.05 sec)
有一个商店的数据,记录客户及购物情况,有以下三个表组成:
- 商品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)
要求:
- 每个表的主外键
- 客户的姓名不能为空值
- 邮箱不能重复
- 客户的性别(男,女)
-- 创建数据库
create database if not exists bit32mall
default character set utf8 ;
-- 选择数据库
use bit32mall;
-- 创建数据库表
-- 商品
create table if not exists goods
(
goods_id int primary key auto_increment comment '商品编号',
goods_name varchar(32) not null comment '商品名称',
unitprice decimal not null default 0 comment '单价,单位分',
category varchar(12) comment '商品分类',
provider enum('供应商A','供应商B') not null comment '供应商名称'
);
-- 客户
create table if not exists customer
(
customer_id int primary key auto_increment comment '客户编号',
name varchar(32) not null comment '客户姓名',
address varchar(256) comment '客户地址',
email varchar(64) unique key comment '电子邮箱',
sex enum('男','女') not null comment '性别',
card_id char(18) unique key comment '身份证'
);
-- 购买
create table if not exists purchase
(
order_id int primary key auto_increment comment '订单号',
customer_id int comment '客户编号',
goods_id int comment '商品编号',
nums int default 1 comment '购买数量',
foreign key (customer_id) references customer(customer_id),
foreign key (goods_id) references goods(goods_id)
);