B站 MySQL 陈长宏老师讲课笔记day2
1.DQL查询语句的使用
1)排序查询
语法:order by 字句
order by 排序字段1 排序方式1,排序字段2 排序方式2......
排序方式:
ASC:升序,默认的
DESC:降序
注意:如果有多个排序条件,则当前面的条件值一样时,才会判断第二条件
按照数学成绩排名(默认升序)
SELECT * FROM student ORDER BY math;
SELECT * FROM student ORDER BY math ASC;
按照数学成绩降序排名
SELECT * FROM student ORDER BY math DESC;
按照数学成绩升序排名,数学成绩一样的,按照英语成绩的降序排名
SELECT * FROM student ORDER BY math ASC,english DESC;
2)聚合查询
将一列数据作为一个整体,进行纵向的计算
count:计算个数
一般选择非空的列:选择主键
count(*):只要这一列数据有一个不为null,就能够算一个记录
max:计算最大值
min:计算最小值
sum:计算和
avg:计算平均值
注意:聚合函数的计算,会排除非null值
解决方案:1.选择不包含非空的列进行计算
2.使用IFNULL函数
计算学生总人数
SELECT COUNT(NAME) FROM student;
计算英语学科人数(非空被排除)
SELECT COUNT(english) FROM student;
解决办法:
SELECT COUNT(IFNULL(english,0)) FROM student;
计算数学成绩的最大值
SELECT MAX(math) FROM student;
计算数学成绩的最小值
SELECT MIN(math) FROM student;
计算数学成绩的和
SELECT SUM(math) FROM student;
计算数学和英语的总和
SELECT SUM(math+english) FROM student;
计算数学的平均分
SELECT AVG(math) FROM student;
3)分组查询
语法:group by 分组字段;
注意:
1.分组之后只能查询的字段:分组字段、聚合函数
2.where和having的区别
1.where 在分组之前限定,如果不满足条件,则不参与分组,having在分组之后进行限定,如果不满足条件,则不会被查询出来
2.where后不可以跟聚合函数,having可以进行聚合函数的判断
按照性别分组,分别查询男、女同学的平均分
SELECT sex ,AVG(math) FROM student GROUP BY sex;
按照性别分组,分别查询男、女同学数学的平均分,人数
SELECT sex ,AVG(math),COUNT(id) FROM student GROUP BY sex;
按照性别分组,分别查询男、女同学数学的平均分、人数,要求分数低于70分的人不参与分组
SELECT sex ,AVG(math),COUNT(id) FROM student WHERE math > 70 GROUP BY sex;
按照性别分组,分别查询男、女同学数学的平均分,人数,要求,分数低于70分的人不参与分组,分组后人数大于两个(分完组后对结果集,再限定一次)
SELECT sex ,AVG(math),COUNT(id) FROM student WHERE math > 70 GROUP BY sex HAVING COUNT(id) > 2;
按照性别分组,分别查询男、女同学数学的平均分,人数,要求,分数低于70分的人不参与分组,分组后人数大于两个,人数是起别名方式,AS省略
SELECT sex ,AVG(math),COUNT(id) 人数 FROM student WHERE math > 70 GROUP BY sex HAVING 人数 > 2;
4)分页查询
1.语法:limit 开始的索引,每页查询的条数
2.公式:开始的索引 =(想看的页码 - 1)* 每页显示的条数
每页显示三条记录,查看第一页内容
SELECT * FROM student LIMIT 0,3;
查看第二页内容
SELECT * FROM student LIMIT 3,3;
3.limit语法 是一个MySQL “方言”,既limit只在MySQL中是分页的语法
2.约束
1)概念:
对表中的数据进行限定,从而保证数据的正确性、有效性和完整性
例如上面的学生表写入数据可以不写姓名,而写入其他内容,但是查询时是没有此人的,要对此进行约束
约束分类:
主键约束:primary key
非空约束:not null
唯一约束:unique
外键约束:foreign key
2)非空约束:not null
1.创建表时添加非空约束
CREATE TABLE stu (
id INT,
NAME VARCHAR(20) NOT NULL -- name为非空约束
);
mysql> INSERT INTO stu(id,name) VALUES(1,'zhangsan');# 向表中写入数据 Query OK, 1 row affected (0.01 sec) mysql> select * from stu;# 正常写入 +------+----------+ | id | name | +------+----------+ | 1 | zhangsan | +------+----------+ 1 row in set (0.00 sec) mysql> INSERT INTO stu(id) VALUES(2);# 当向表中写入id数据而不写入name时报错 ERROR 1364 (HY000): Field 'name' doesn't have a default value mysql> select * from stu;# 数据没有写入 +------+----------+ | id | name | +------+----------+ | 1 | zhangsan | +------+----------+ 1 row in set (0.00 sec)
2.删除非空约束
ALTER TABLE 表名 MODIFY 列号 类型;
mysql> ALTER TABLE stu MODIFY NAME VARCHAR(20);# 修改约束 Query OK, 1 row affected (0.02 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> INSERT INTO stu(id) VALUES(2);# 写入数据只有id未报警 Query OK, 1 row affected (0.00 sec) mysql> select * from stu;# 写入到表中 +------+----------+ | id | NAME | +------+----------+ | 1 | zhangsan | | 2 | NULL | +------+----------+ 2 rows in set (0.00 sec) mysql> desc stu;# 查看规则,name列是可以为空的 +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | | NAME | varchar(20) | YES | | NULL | | +-------+-------------+------+-----+---------+-------+ 2 rows in set (0.01 sec)
3.创建表完后添加非空约束
mysql> ALTER TABLE stu MODIFY NAME VARCHAR(20) NOT NULL;# 对name添加约束条件 ERROR 1265 (01000): Data truncated for column 'NAME' at row 2 mysql> select * from stu;# 报错是因为将要约束非空的name列有一空行 +------+----------+ | id | NAME | +------+----------+ | 1 | zhangsan | | 2 | NULL | +------+----------+ 3 rows in set (0.00 sec) mysql> DELETE FROM stu WHERE id=2;# 删除name列为空的行 Query OK, 2 rows affected (0.01 sec) mysql> select * from stu; +------+----------+ | id | NAME | +------+----------+ | 1 | zhangsan | +------+----------+ 1 row in set (0.00 sec) mysql> ALTER TABLE stu MODIFY NAME VARCHAR(20) NOT NULL;# 再次添加约束规则,添加成功 Query OK, 1 row affected (0.02 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> desc stu;# 查看规则,name列不能为空 +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | | NAME | varchar(20) | NO | | NULL | | +-------+-------------+------+-----+---------+-------+ 2 rows in set (0.01 sec)
3)唯一约束:unique
1.创建表时添加唯一约束
CREATE TABLE stu(
id int,
phone_number varchar(20) unique
);
mysql> desc stu;# 唯一约束下面phone_number有显示 +--------------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------------+-------------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | | phone_number | varchar(20) | YES | UNI | NULL | | +--------------+-------------+------+-----+---------+-------+ 2 rows in set (0.01 sec) mysql> INSERT INTO stu(id,phone_number) VALUES(1,1111);# 写入一条数据 Query OK, 1 row affected (0.01 sec) mysql> INSERT INTO stu(id,phone_number) VALUES(2,1111);# 再写入一行数据phone_number相同,出现唯一报错 ERROR 1062 (23000): Duplicate entry '1111' for key 'phone_number' mysql> SELECT * FROM STU;# 第二次数据也没有写入 +------+--------------+ | id | phone_number | +------+--------------+ | 1 | 1111 | +------+--------------+ 1 row in set (0.00 sec) mysql> INSERT INTO stu(id,phone_number) VALUES(2,1112);# 把phone_number号更改后可以写入 Query OK, 1 row affected (0.01 sec) mysql> SELECT * FROM STU; +------+--------------+ | id | phone_number | +------+--------------+ | 1 | 1111 | | 2 | 1112 | +------+--------------+ 2 rows in set (0.00 sec) mysql> INSERT INTO stu(id) VALUES(3);# id为3,没有phone_number Query OK, 1 row affected (0.01 sec) mysql> INSERT INTO stu(id) VALUES(4);# id为4,也没有phone_number,但可以写入,可以理解为null代表着不确定性,两个null都不确定,互相之间不重复,所以与唯一性不冲突 Query OK, 1 row affected (0.00 sec) mysql> SELECT * FROM STU; +------+--------------+ | id | phone_number | +------+--------------+ | 1 | 1111 | | 2 | 1112 | | 3 | NULL | | 4 | NULL | +------+--------------+ 4 rows in set (0.00 sec) mysql> desc stu;# 唯一约束被删除 +--------------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------------+-------------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | | phone_number | varchar(20) | YES | | NULL | | +--------------+-------------+------+-----+---------+-------+ 2 rows in set (0.01 sec)
2.删除唯一约束(唯一约束也叫索引约束)
ALTER TABLE 表名 drop index 列号;
mysql> ALTER TABLE stu MODIFY phone_number VARCHAR(20);# 使用非空约束的修改方式,显示成功了 Query OK, 0 rows affected (0.01 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> INSERT INTO stu(id,phone_number) VALUES(5,1111);# 但是写入数据,仍然出现报错 ERROR 1062 (23000): Duplicate entry '1111' for key 'phone_number' mysql> SELECT * FROM STU;# 未写入数据 +------+--------------+ | id | phone_number | +------+--------------+ | 1 | 1111 | | 2 | 1112 | | 3 | NULL | | 4 | NULL | +------+--------------+ 4 rows in set (0.00 sec) mysql> ALTER TABLE stu drop index phone_number;# 删除索引约束,显示成功 Query OK, 0 rows affected (0.01 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> INSERT INTO stu(id,phone_number) VALUES(5,1111);# 重复数据可以写入,唯一约束被删除 Query OK, 1 row affected (0.01 sec) mysql> SELECT * FROM STU; +------+--------------+ | id | phone_number | +------+--------------+ | 1 | 1111 | | 2 | 1112 | | 3 | NULL | | 4 | NULL | | 5 | 1111 | +------+--------------+ 5 rows in set (0.00 sec)
3.创建表完后添加唯一约束
mysql> ALTER TABLE stu MODIFY phone_number VARCHAR(20) unique;# 添加规则,发现报错,与非空约束一样,原表中有重复数据111 ERROR 1062 (23000): Duplicate entry '1111' for key 'phone_number' mysql> SELECT * FROM STU; +------+--------------+ | id | phone_number | +------+--------------+ | 1 | 1111 | | 2 | 1112 | | 3 | NULL | | 4 | NULL | | 5 | 1111 | +------+--------------+ 5 rows in set (0.00 sec) mysql> DELETE FROM stu WHERE id=5;# 删除重复数据 Query OK, 1 row affected (0.01 sec) mysql> ALTER TABLE stu MODIFY phone_number VARCHAR(20) unique;# 创建表后添加唯一约束 Query OK, 0 rows affected (0.02 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> INSERT INTO stu(id,phone_number) VALUES(5,1111);# 测试,重复数据无法写入,唯一约束添加成功 ERROR 1062 (23000): Duplicate entry '1111' for key 'phone_number'
4)主键约束:primary key
1.注意:
1.含义:非空且唯一(上面非空约束唯一约束的集合)
2.一张表只能有一个字段为主键
3.主键就是表中的唯一标识
2.在创建表时,添加主键约束
CREATE TABLE stu(
id int primary key ,-- 给ID添加主键约束
name varchar(20)
);
mysql> use db1 Database changed mysql> mysql> select database(); +------------+ | database() | +------------+ | db1 | +------------+ 1 row in set (0.00 sec) mysql> CREATE TABLE stu(id int primary key, -- 给ID添加主键约束 -> name varchar(20)); Query OK, 0 rows affected (0.01 sec) mysql> INSERT stu(id,name) VALUES(1,'zhangsan');# 添加一条数据 Query OK, 1 row affected (0.00 sec) mysql> select * from stu;# 数据添加成功 +----+----------+ | id | name | +----+----------+ | 1 | zhangsan | +----+----------+ 1 row in set (0.00 sec) mysql> INSERT stu(id,name) VALUES(1,'lisi');# 测试id是否唯一约束,id=1已有,添加不成功 ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY' mysql> INSERT stu(name) VALUES('wangwu');# 测试id是否非空约束,id不得为空,添加不成功 ERROR 1364 (HY000): Field 'id' doesn't have a default value mysql> INSERT stu(id,name) VALUES(5,'maliu');# 唯一的id,并且不为空可以添加成功 Query OK, 1 row affected (0.01 sec) mysql> select * from stu; +----+----------+ | id | name | +----+----------+ | 1 | zhangsan | | 5 | maliu | +----+----------+ 2 rows in set (0.00 sec) mysql> desc stu;# 查看key约束为PRI +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | int(11) | NO | PRI | NULL | | | name | varchar(20) | YES | | NULL | | +-------+-------------+------+-----+---------+-------+ 2 rows in set (0.01 sec)
3.删除主键约束
ALTER TABLE 表名 DROP primary key;
mysql> ALTER TABLE stu MODIFY id int;# MODIFY连唯一约束都删除不了,自然更删除不了主键约束 Query OK, 0 rows affected (0.00 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> INSERT stu(id,name) VALUES(1,'lisi');# 仍然无法写入数据 ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY' mysql> desc stu;# 主键约束依然存在 +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | int(11) | NO | PRI | 0 | | | name | varchar(20) | YES | | NULL | | +-------+-------------+------+-----+---------+-------+ 2 rows in set (0.00 sec) mysql> ALTER TABLE stu DROP primary key;# 删除不需要指定列名,是因为主键约束在一张表中只能有一个,所以不用指定列名 Query OK, 2 rows affected (0.01 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> INSERT stu(id,name) VALUES(1,'lisi');# 可以写入重复数据 Query OK, 1 row affected (0.00 sec) mysql> SELECT * FROM stu;# ID=1为重复数据 +----+----------+ | id | name | +----+----------+ | 1 | zhangsan | | 5 | maliu | | 1 | lisi | +----+----------+ 3 rows in set (0.00 sec) mysql> desc stu;# 主键约束已被删除 +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | int(11) | NO | | 0 | | | name | varchar(20) | YES | | NULL | | +-------+-------------+------+-----+---------+-------+ 2 rows in set (0.01 sec)
4.创建完表后添加主键约束
mysql> SELECT * FROM stu;# 原表数据 +----+----------+ | id | name | +----+----------+ | 1 | zhangsan | | 5 | maliu | | 1 | lisi | +----+----------+ 3 rows in set (0.00 sec) mysql> ALTER TABLE stu MODIFY id int primary key;# 添加主键约束,发现添加不成功,因为id不唯一 ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY' mysql> delete from stu where name='lisi';# 删除其中一个id,使id=1,成为唯一值 Query OK, 1 row affected (0.00 sec) mysql> INSERT stu(id,name) VALUES(1,'lisi');# 添加id=1的值,无法添加 ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY' mysql> desc stu;# 主键约束又添加成功 +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | int(11) | NO | PRI | NULL | | | name | varchar(20) | YES | | NULL | | +-------+-------------+------+-----+---------+-------+ 2 rows in set (0.01 sec)
5.自动增长auto_increment
1.概念:如果某一列是数值类型的,使用auto_increment 可以来完成自动增长
比如输入id,让他完成自增长,而不是每次都去查询,然后写入,并且自增长只和上一条数据有关系。
2.在创建表时,添加主键约束,并且完成主键自增长
CREATE TABLE stu(id int primary key auto_increment,name varchar(20) ); -- 给ID添加主键约束以及自增长
mysql> CREATE TABLE stu(id int primary key auto_increment,name varchar(20) ); Query OK, 0 rows affected (0.01 sec) mysql> INSERT stu(id,name) VALUES(1,'zhangsan');# 添加第一行数据 Query OK, 1 row affected (0.01 sec) mysql> INSERT stu(id,name) VALUES(null,'zhangsan');# 第二行不输入id,未报错 Query OK, 1 row affected (0.01 sec) mysql> INSERT stu(id,name) VALUES(null,'lisi');# 第三行也为输入id Query OK, 1 row affected (0.01 sec) mysql> INSERT stu(id,name) VALUES(9,'wangwu');# 直接输入id=9 Query OK, 1 row affected (0.01 sec) mysql> INSERT stu(name) VALUES('liiuliu');# 直接输入数据,未写id,未写null Query OK, 1 row affected (0.01 sec) mysql> select * from stu;# null和不写,都会自动自增1生成ID号,自增是在上一个id基础上自增的。 +----+----------+ | id | name | +----+----------+ | 1 | zhangsan | | 2 | zhangsan | | 3 | lisi | | 9 | wangwu | | 10 | liiuliu | +----+----------+ 5 rows in set (0.00 sec)
3.删除自增长,再删除主键约束
ALTER TABLE stu MODIFY id int;
ALTER TABLE stu DROP primary key;
4.创建完表后添加自增长
ALTER TABLE stu MODIFY id int auto_increment; # 一般自增长和主键约束一起使用
5)外键约束:foreign key
1.外键约束介绍
CREATE TABLE emp ( -- 创建 emp 表 id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(30), age INT, dep_name VARCHAR(30), -- 部门名称 dep_location VARCHAR(30) -- 部门地址 ); INSERT INTO emp(NAME,age,dep_name,dep_location) VALUES('张三',20,'研发部','广州'); INSERT INTO emp(NAME,age,dep_name,dep_location) VALUES('李四',21,'研发部','广州'); INSERT INTO emp(NAME,age,dep_name,dep_location) VALUES('王五',20,'研发部','广州'); INSERT INTO emp(NAME,age,dep_name,dep_location) VALUES('老王',20,'销售部','深圳'); INSERT INTO emp(NAME,age,dep_name,dep_location) VALUES('大王',22,'销售部','深圳'); INSERT INTO emp(NAME,age,dep_name,dep_location) VALUES('小王',18,'销售部','深圳');
上表中发现重复的数据有很多,比如广州、深圳,我们将重复的数据称为冗余数据
当要修改部门或者地点一条数据的时候,要将所有冗余数据都修改,非常不方便
解决方法:做一个表的拆分,一张表存放员工的信息,另外一张表专门存放部门的信息,然后让员工表和部门表相关联
创建部门表(id,dep_name,dep_location)
一方,主表
CREATE TABLE department ( id INT PRIMARY KEY AUTO_INCREMENT, dep_name VARCHAR(20), dep_location VARCHAR(30) );
创建员工表(id,name,dep_id)
多方,从表
CREATE TABLE employee ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(20), age int, dep_id INT -- 外键对应主表的主键 );
添加两个部门
INSERT INTO department VALUES(NULL,'研发部','广州'),(NULL,'销售部','深圳');
添加员工,dep_id 表示员工所在部门
INSERT INTO employee (NAME,age,dep_id) VALUES('张三',20,1); INSERT INTO employee (NAME,age,dep_id) VALUES('李四',21,1); INSERT INTO employee (NAME,age,dep_id) VALUES('王五',20,1); INSERT INTO employee (NAME,age,dep_id) VALUES('老王',20,2); INSERT INTO employee (NAME,age,dep_id) VALUES('大王',22,2); INSERT INTO employee (NAME,age,dep_id) VALUES('小王',18,2);
SELECT * FROM employee; SELECT * FROM department;
我们可以通过两个表知道对应信息,但是当开发项目完毕后,要删除开发部门时,直接就可以删除,张三李四王五还在开发部门,但开发部删除后已经看不到他们属于哪个部门了,所以我们要设定先把这个部门的人删除或转移后,才能删除部门,这就需要用到外键约束了。
2.外键约束:
foreign key:让表与表产生关系,从而保证数据的正确性。
1.在创建表时,可以添加外键
语法:
create table 表名( ...... # 内容 外键列 constraint 外键名称 foreign key (外键列名称) references 主表名称(主表列名称) );
先删除原先的表
DROP TABLE employee; DROP TABLE emp; DROP TABLE department;
CREATE TABLE department ( id INT PRIMARY KEY AUTO_INCREMENT, dep_name VARCHAR(20), dep_location VARCHAR(30) ); # 因为外键约束是employee表添加到department表中,所以要先创建department表 CREATE TABLE employee ( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(20), age INT, dep_id INT, -- 外键对应主表的主键(注意:因为加了一行,所以此行不是最后一行,要加,) CONSTRAINT emp_dept_fk FOREIGN KEY (dep_id) REFERENCES department(id) ); INSERT INTO department VALUES(NULL,'研发部','广州'),(NULL,'销售部','深圳'); INSERT INTO employee (NAME,age,dep_id) VALUES('张三',20,1); INSERT INTO employee (NAME,age,dep_id) VALUES('李四',21,1); INSERT INTO employee (NAME,age,dep_id) VALUES('王五',20,1); INSERT INTO employee (NAME,age,dep_id) VALUES('老王',20,2); INSERT INTO employee (NAME,age,dep_id) VALUES('大王',22,2); INSERT INTO employee (NAME,age,dep_id) VALUES('小王',18,2);
mysql> DELETE FROM department WHERE ID=1;# 再次删除,发现报警,报警内容是这一行被外键引用 ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (db1.employee, CONSTRAINT emp_dept_fk FOREIGN KEY (dep_id) REFERENCES department (id)) mysql> INSERT INTO employee(NAME,age,dep_id) VALUES('wang',22,5);# 主表也不能添加除外键约束的其他内容,比如:id=5就想添加但是添加不成功 ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`db1`.`employee`, CONSTRAINT `emp_dept_fk` FOREIGN KEY (`dep_id`) REFERENCES `department` (`id`)) mysql> INSERT INTO employee(NAME,age,dep_id) VALUES('wang',22,2);# 当添加主表有的约束的数据,就可以添加成功了 Query OK, 1 row affected (0.01 sec) mysql> desc employee; +--------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------+-------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(20) | YES | | NULL | | | age | int(11) | YES | | NULL | | | dep_id | int(11) | YES | MUL | NULL | | +--------+-------------+------+-----+---------+----------------+ 4 rows in set (0.01 sec)
2.删除外键
ALTER TABLE 主表 DROP FOREIGN KEY 列名;
mysql> ALTER TABLE employee DROP FOREIGN KEY emp_dept_fk;# 删除外键约束 Query OK, 7 rows affected (0.01 sec) Records: 7 Duplicates: 0 Warnings: 0 mysql> INSERT INTO employee(NAME,age,dep_id) VALUES('wang',22,5);# 添加内容,id号不被约束 Query OK, 1 row affected (0.01 sec)
3.创建表后,添加外键
ALTER TABLE 主表 ADD CONSTRAINT 外键名称 FOREIGN KEY (外键列名) REFERENCES 主表(列名);
mysql> ALTER TABLE employee ADD CONSTRAINT emp_dept_fk FOREIGN KEY (dep_id) REFERENCES department(id);# 因为dep_id=5,副表中没有,所以报错 ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (db1.#sql-4b4c_4, CONSTRAINT emp_dept_fk FOREIGN KEY (dep_id) REFERENCES department (id)) mysql> select * from employee;# 查看一下确实dep_id中有5 +----+--------+------+--------+ | id | name | age | dep_id | +----+--------+------+--------+ | 1 | 寮犱笁 | 20 | 1 | | 2 | 鏉庡洓 | 21 | 1 | | 3 | 鐜嬩簲 | 20 | 1 | | 4 | 鑰佺帇 | 20 | 2 | | 5 | 澶х帇 | 22 | 2 | | 6 | 灏忕帇 | 18 | 2 | | 8 | wang | 22 | 2 | | 9 | wang | 22 | 5 | +----+--------+------+--------+ 8 rows in set (0.00 sec) mysql> DELETE FROM employee WHERE ID=9;# 删除dep_id=5的数据 Query OK, 1 row affected (0.01 sec) mysql> ALTER TABLE employee ADD CONSTRAINT emp_dept_fk FOREIGN KEY (dep_id) REFERENCES department(id); Query OK, 5 rows affected (0.01 sec) Records: 5 Duplicates: 0 Warnings: 0 mysql> INSERT INTO employee(NAME,age,dep_id) VALUES('wang',22,5);# 再次添加出现报错,证明外键约束添加成功 ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`db1`.`employee`, CONSTRAINT `emp_dept_fk` FOREIGN KEY (`dep_id`) REFERENCES `department` (`id`))
3.级联操作
级联操作就是一些联动的操作,可以在已添加外键约束的情况下,添加级联操作,上面中当设置外键约束后,id=5就不能够添加到附表中了,但是又有一些需要更改id=5的操作,所以可以设置级联,可以在添加外键时设置级联,也可以创建表后更新级联
1.以下是未使用级联操作时,更改数字的操作
mysql> SELECT * FROM employee; +----+--------+------+--------+ | id | name | age | dep_id | +----+--------+------+--------+ | 1 | 寮犱笁 | 20 | 1 | | 2 | 鏉庡洓 | 21 | 1 | | 3 | 鐜嬩簲 | 20 | 1 | | 4 | 鑰佺帇 | 20 | 2 | | 6 | 灏忕帇 | 18 | 2 | +----+--------+------+--------+ 5 rows in set (0.00 sec) mysql> UPDATE employee SET dep_id = NULL WHERE dep_id = 1; Query OK, 3 rows affected (0.01 sec) Rows matched: 3 Changed: 3 Warnings: 0 mysql> SELECT * FROM employee;# 外键约束后,可以为null,但不可以为外键约束值外的其他值 +----+--------+------+--------+ | id | name | age | dep_id | +----+--------+------+--------+ | 1 | 寮犱笁 | 20 | NULL | | 2 | 鏉庡洓 | 21 | NULL | | 3 | 鐜嬩簲 | 20 | NULL | | 4 | 鑰佺帇 | 20 | 2 | | 6 | 灏忕帇 | 18 | 2 | +----+--------+------+--------+ 5 rows in set (0.00 sec) mysql> SELECT * FROM department;# 此时外键约束1和2还在约束主表的1,2,但不约束null +----+-----------+--------------+ | id | dep_name | dep_location | +----+-----------+--------------+ | 1 | 研发部 |广州 | | 2 | 销售部 | 深圳 | +----+-----------+--------------+ 2 rows in set (0.00 sec) mysql> UPDATE department SET id = 5 WHERE id = 1;# 因为主表没有1了,把副表约束id=1改为id=5 Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> SELECT * FROM department;# 当附表约束id=5后,主表就可以更改null为5了 +----+-----------+--------------+ | id | dep_name | dep_location | +----+-----------+--------------+ | 2 | 销售部 | 深圳 | | 5 | 研发部 |广州 | +----+-----------+--------------+ 2 rows in set (0.00 sec) mysql> UPDATE employee SET dep_id = 5 WHERE dep_id IS NULL; Query OK, 3 rows affected (0.01 sec) Rows matched: 3 Changed: 3 Warnings: 0 mysql> SELECT * FROM employee;# 先更改主表为null,再改副表为值,最后再把主表由null改为附表的值 +----+--------+------+--------+ | id | name | age | dep_id | +----+--------+------+--------+ | 1 | 寮犱笁 | 20 | 5 | | 2 | 鏉庡洓 | 21 | 5 | | 3 | 鐜嬩簲 | 20 | 5 | | 4 | 鑰佺帇 | 20 | 2 | | 6 | 灏忕帇 | 18 | 2 | +----+--------+------+--------+ 5 rows in set (0.00 sec)
2.级联操作
1.在添加外键时设置级联更新
mysql> ALTER TABLE employee DROP FOREIGN KEY emp_dept_fk;# 删除外键约束 Query OK, 5 rows affected (0.01 sec) Records: 5 Duplicates: 0 Warnings: 0 mysql> ALTER TABLE employee ADD CONSTRAINT emp_dept_fk FOREIGN KEY (dep_id) REFERENCES department(id) ON UPDATE CASCADE;# 添加外键约束+级联更新 Query OK, 5 rows affected (0.01 sec) Records: 5 Duplicates: 0 Warnings: 0 mysql> SELECT * FROM employee;# 原主表 +----+--------+------+--------+ | id | name | age | dep_id | +----+--------+------+--------+ | 1 | 寮犱笁 | 20 | 5 | | 2 | 鏉庡洓 | 21 | 5 | | 3 | 鐜嬩簲 | 20 | 5 | | 4 | 鑰佺帇 | 20 | 2 | | 6 | 灏忕帇 | 18 | 2 | +----+--------+------+--------+ 5 rows in set (0.00 sec) mysql> SELECT * FROM department;# 原副表 +----+-----------+--------------+ | id | dep_name | dep_location | +----+-----------+--------------+ | 2 | 销售部 | 深圳 | | 5 | 研发部 |广州 | +----+-----------+--------------+ 2 rows in set (0.00 sec) mysql> UPDATE department SET dep_id = 1 WHERE dep_id = 5;# 当对副表添加外键约束和级联更新后 ERROR 1054 (42S22): Unknown column 'dep_id' in 'where clause' mysql> UPDATE department SET id = 1 WHERE id = 5;# 更新副表 Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> SELECT * FROM department;# 副表id=5发生更改id=1 +----+-----------+--------------+ | id | dep_name | dep_location | +----+-----------+--------------+ | 1 | 研发部 |广州 | | 2 | 销售部 | 深圳 | +----+-----------+--------------+ 2 rows in set (0.00 sec) mysql> SELECT * FROM employee;# 同时,未对主表id进行任何操作,主表对应的副表中约束内容也变成了副表更改后的内容 +----+--------+------+--------+ | id | name | age | dep_id | +----+--------+------+--------+ | 1 | 寮犱笁 | 20 | 1 | | 2 | 鏉庡洓 | 21 | 1 | | 3 | 鐜嬩簲 | 20 | 1 | | 4 | 鑰佺帇 | 20 | 2 | | 6 | 灏忕帇 | 18 | 2 | +----+--------+------+--------+ 5 rows in set (0.00 sec)
2.级联删除,当副表中id=1的行删除,相对应的主表中对应关联的行也会被删除
mysql> ALTER TABLE employee DROP FOREIGN KEY emp_dept_fk;# 删除外键约束 Query OK, 5 rows affected (0.01 sec) Records: 5 Duplicates: 0 Warnings: 0 mysql> ALTER TABLE employee ADD CONSTRAINT emp_dept_fk FOREIGN KEY (dep_id) REFERENCES department(id) ON UPDATE CASCADE ON DELETE CASCADE;# 添加级联删除 Query OK, 5 rows affected (0.01 sec) Records: 5 Duplicates: 0 Warnings: 0 mysql> SELECT * FROM employee; +----+--------+------+--------+ | id | name | age | dep_id | +----+--------+------+--------+ | 1 | 寮犱笁 | 20 | 1 | | 2 | 鏉庡洓 | 21 | 1 | | 3 | 鐜嬩簲 | 20 | 1 | | 4 | 鑰佺帇 | 20 | 2 | | 6 | 灏忕帇 | 18 | 2 | +----+--------+------+--------+ 5 rows in set (0.00 sec) mysql> SELECT * FROM department; +----+-----------+--------------+ | id | dep_name | dep_location | +----+-----------+--------------+ | 1 | 研发部 |广州 | | 2 | 销售部 | 深圳 | +----+-----------+--------------+ 2 rows in set (0.00 sec) mysql> DELETE FROM department WHERE id = 1;# 当删除副表中id=1行时 Query OK, 1 row affected (0.01 sec) mysql> SELECT * FROM department;# 副表中id=1的行已删除 +----+-----------+--------------+ | id | dep_name | dep_location | +----+-----------+--------------+ | 2 | 销售部 | 深圳 | +----+-----------+--------------+ 1 row in set (0.00 sec) mysql> SELECT * FROM employee;# 主表中id=1的行也被删除 +----+--------+------+--------+ | id | name | age | dep_id | +----+--------+------+--------+ | 4 | 鑰佺帇 | 20 | 2 | | 6 | 灏忕帇 | 18 | 2 | +----+--------+------+--------+ 2 rows in set (0.00 sec)
4.级联操作总结
1.添加级联操作
语法:ALTER TABLE 主表名 ADD CONSTRAINT 外键名称 FOREIGN KEY (主表关联列名) REFERENCES 副表(关联列名) ON UPDATE CASCADE ON DELETE CASCADE;
2.分类
1.级联更新:ON UPDATE CASCADE
2.级联删除:ON DELETE CASCADE
优势与弊端:1.方便,2.当多表相关联时,删除其中一个表,其他相关联表中对应的数据也会被删除
3.数据库的设计
设计数据库,会间接影响软件开发的难易程度,数据库设计的越合理,软件开发速度越快
1.多表之间的关系
1)分类:
1.一对一的关系:
如:人和身份证的关系
分析:一个人只有一张身份证,一张身份证只能对应一个人
2.一对多(或多对一)的关系
如:部门和员工
分析:一个部门有多个员工,一个员工只能对应一个部门
3.多对多的关系
如:学生和课程
分析:一个学生可以选择很多门课程,一个课程也可以被很多学生选择
2)实现关系:
1.一对多(多对一):
如:部门和员工
实现方式:在多的一方建立外键,指向一的一方的主键
2.多对多:多对多关系实现需要借助第三张中间表
实现方式:中间表至少包含两个字段,这两个字段作为第三张表的外键,分别指向两张主表的主键。
3.一对多的关系:
如:人和身份证的关系
实现方式:一对一关系实现,可以在任意一方添加唯一外键指向另一方的主键(若不是唯一外键,就变成了一对多情况)
3)案例
例如途牛旅游,一个旅游路线分类(起点、终点)可以对应多个旅游线路(水、陆、空),所以是一对多的关系,多条旅游线路可以被多个用户收藏,所以是多对多的关系,多对多要借助中间表,至少要对两张主表的主键列为中间表的列,再进行多多对应。
-- 创建旅游线路分类表,tab_category -- cid 路由路线分类主键约束,自动增长 -- cname 旅游路线分类名称非空,唯一,字符串 100 CREATE TABLE tab_category ( cid INT PRIMARY KEY AUTO_INCREMENT, cname VARCHAR(100) NOT NULL UNIQUE ); -- 添加旅游线路分类数据 INSERT INTO tab_category (cname) VALUES ('周边游'),('出境游'),('国内游'),('港澳游'); SELECT * FROM tab_category; -- 创建旅游线路表 tab_category /* rid 旅游线路主键约束,自动增长 rname 旅游线路名称非空,唯一,字符串100 price 价格 rdate 上架时间,日期类型 cid 外键,所属分类(对上面表cid的外键约束)(下面未指定外键名称,但会默认生成唯一的一个外键名称) */ CREATE TABLE tab_route( rid int primary key auto_increment, rname varchar(100) not null unique, price double, rdate date, cid int, foreign key (cid) references tab_category(cid) ); -- 创建用户表tab_user /* uid 用户主键,自增长 username 用户长度100,唯一,非空 password 密码长度30,非空 name 真实姓名,长度100 birthday 生日 sex 性别,定长字符串1 telephone 手机号,字符串11 email 邮箱,字符串长度200 */ CREATE TABLE tab_user ( uid int primary key auto_increment, username varchar(100) not null unique, password varchar(30) not null, name varchar(100), birthday date, sex char(1) default '男', telephone varchar(11), email varchar(100) ); /* 创建收藏表tab_favorite rid 旅游路线id,外键 date 收藏时间 uid 用户id,外键 rid和uid不能重复,设置复合主键,同一个用户不能收藏同一个线路两次 */ CREAT date datetime, uid int, -- 用户id -- 创建复合主键 PRIMARY KEY(rid,uid), -- 联合主键的操作 foreign key (rid) references tab_route(rid), foreign key (uid) references tab_user(uid), );
2.数据库设计的范式
1)概念
设计数据库时需要遵循的一些规范,要遵循后边的范式,必须先遵循前边的所有范式要求
设计关系数据库时,遵从不同的规范要求,设计出合理的关系型数据库,这些不同的规范要求被称为不同的范式,各种范式呈递次规范,越高的范式数据库冗余越小
关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)
2)分类
类似布置作业,第一擦桌子,第二擦桌子+扫地,第三擦桌子+扫地+擦黑板,这就是前面所说的递次规范,要干后面的,前面比如要先干完
第一范式(1NF):每一列都是不可分割的原子数据项
第二范式(2NF):在1NF的基础上,非码属性必须完全依赖于候选码(在1NF基础上消除非主属性对主码的部分函数依赖)
概念:
a.函数依赖:A--->B,如果通过A属性(属性组)的值,可以确定唯一B属性的值,则称B依赖于A
例如:学号-->姓名(通过学号就可以确定姓名)(属性组,例如通过学号没办法确定分数,因为学号和分数的对应不唯一,例如张无忌有三个分数,但可以通过学号和课程名称确定分数,所以就称学号和课程名称为属性组)
b.完全函数依赖:A--->B,如果A是一个属性组,则B属性值得确定需要依赖于A属性组中所有的属性值
例如:(学号,课程名称)---> 分数
c.部分函数依赖:如果A是一个属性组,则B属性值得确定只需要依赖于A属性组中某一些值既可
例如:(学号或课程名称)---> 姓名
d.传递函数依赖:A--->B,B--->C,如果通过A属性(属性组)的值,可以确定唯一B属性的值,再通过B属性(属性组)的值,可以确定唯一C属性的值,则称C传递函数依赖与A
例如:由学号查找到系名,可以说系名依赖了学号,再由系名可以查找到系主任,就可以说系主任传递依赖于学号
e.码:如果在一张表中,一个属性或属性组,被其他所有属性所完全依赖,则称这个属性(属性组)为该表的码
例如:该表中码为:属性组(学号和课程名称)
主属性:码属性组中的所有属性
非主属性:除过码属性组的属性
第三范式(3NF):在2NF基础上,任何非主属性不依赖于其它非主属性(在2NF基础上消除传递依赖)
3)详细介绍
1.与第一范式进行对照,以上是一张很常见的表,我们与第一范式进行对照,发现不符合第一范式,因为系的列又进行了分割,把表进行调整,变成第一范式类型的表
但是上表还存在问题:
1.存在非常严重数据冗余,学号,姓名,系名,系主任等过多重复
2.数据添加存在问题,例如新开设的系和系主任时,还没有学生,添加数据不合法
3.数据删除也存在问题,例如张无忌毕业了,删除数据,会将系名、系主任的数据一起删除
2.第二范式
上表解决了数据冗余问题,但还存在问题:
1.数据添加存在问题,例如新开设的系和系主任时,还没有学生,添加数据不合法
2.数据删除也存在问题,例如张无忌毕业了,删除数据,会将系名、系主任的数据一起删除
3.第二范式
上表解决了数据添加和数据删除的问题
4.数据库的备份和还原
1)命令行的方式
备份语法:mysqldump -u用户名 -p密码 数据库的名称 > 保存的路径/文件的自定义名称
还原语法:
a.登录数据库
b.创建数据库
c.使用数据库
d.执行文件,source 文件路径
a.备份过程
C:\Users\马俊南>mysql -uroot -proot Welcome to the MySQL monitor. Commands end with ; or \g. ........ # 此处登录信息 Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> show databases;# 查看当前数据库有多少库 +--------------------+ | Database | +--------------------+ | information_schema | | db1 | | db2 | | mysql | | performance_schema | | test | +--------------------+ 6 rows in set (0.01 sec) mysql> exit Bye C:\Users\马俊南>mysqldump -uroot -proot db1 > d:/a.sql
导出的备份文件都是使用过的SQL语句,如下部分SQL展示:
-- MySQL dump 10.13 Distrib 5.5.40, for Win64 (x86) # 安装的系统 -- -- Host: localhost Database: db1 # 本地安装、数据库名称 -- Server version5.5.40 # 数据库版本号 /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT /; /!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS /; /!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION /; /!40101 SET NAMES utf8 */; ....... # 此处省略SQL语句 -- Dump completed on 2022-11-13 23:59:46 # 导出备份文件的时间
b.还原过程
C:\Users\马俊南>mysql -uroot -proot Welcome to the MySQL monitor. Commands end with ; or \g. ........ # 此处登录信息 Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | db1 | | db2 | | mysql | | performance_schema | | test | +--------------------+ 6 rows in set (0.00 sec) mysql> drop database db1; # 删除DB1数据库 Query OK, 4 rows affected (0.02 sec) mysql> show databases; # 确认已删除DB1数据库 +--------------------+ | Database | +--------------------+ | information_schema | | db2 | | mysql | | performance_schema | | test | +--------------------+ 5 rows in set (0.00 sec) mysql> create database db1; # 先创建DB1数据库 Query OK, 1 row affected (0.00 sec) mysql> use db1; Database changed mysql> source d:/a.sql; # 使用备份文件,source还原数据DB1 Query OK, 0 rows affected (0.00 sec) ...... # 中间多条SQL执行成功信息 Query OK, 0 rows affected (0.00 sec) mysql> show tables; # 之前数据库中删除的文件已还原 +---------------+ | Tables_in_db1 | +---------------+ | department | | employee | | stu | | student | +---------------+ 4 rows in set (0.00 sec)
2)图形化工具的方式
a.备份过程
选择要备份的数据库,点击右键,选择备份/导出,备份数据库转储到SQL,选择存放的位置和备份文件的名称,点击导出,点击完成
b.还原过程
选择要还原的数据库区域,点击右键,选择执行SQL脚本,选择存放的SQL脚本,点击执行,执行成功后显示绿色进度条,点击完成,刷新界面
本篇单词:
order:顺序
primary:主要的
unique:唯一的
foreign:对外的
department:部门
employee:员工
constraint:约束
references:参考文献