Javaweb-day02-mysql约束

今日内容–mysql约束

  1. DQL:查询语句
    1. 排序查询
    2. 聚合函数
    3. 分组查询
    4. 分页查询
  2. 约束
  3. 多表之间的关系
  4. 范式
  5. 数据库的备份和还原

学习方法:

mysql这一节属于实操性比较强的知识,内容细而多,必须加强动手练习,才能巩固加强记忆。

一. dql学习

1. 排序查询

  • 语法

    order by 子句
    order by 字段1 排序方式1,字段2 排序方式2,...
    
    注意:
    1.排序方式有2种:升序 asc  降序 desc ,默认升序
    2.如 字段1 和 字段2 排序有冲突,字段1 优先满足。
    3.如字段1数据相同,再按照字段2的排序方式排序。
    

先建一个表,方便后面查看:

DROP TABLE student;
CREATE TABLE `student` (
  `id` INT(11) DEFAULT NULL,
  `NAME` VARCHAR(20) DEFAULT NULL,
  `age` INT(11) DEFAULT NULL,
  `sex` VARCHAR(5) DEFAULT NULL,
  `address` VARCHAR(100) DEFAULT NULL,
  `math` INT(11) DEFAULT NULL,
  `english` INT(11) DEFAULT NULL
) ENGINE=INNODB DEFAULT CHARSET=utf8;
/*Data for the table `student` */
INSERT  INTO `student`(`id`,`NAME`,`age`,`sex`,`address`,`math`,`english`) VALUES 
(1,'马云',55,'男','杭州',66,78),
(2,'马化腾',45,'女','深圳',98,87),
(3,'马景涛',55,'男','香港',56,77),
(4,'柳岩',20,'女','湖南',76,65),
(5,'柳青',20,'男','湖南',NULL,NULL),
(6,'刘德华',57,'男','香港',99,99),
(7,'马德',22,'女','香港',99,99),
(8,'德玛西亚',18,'男','南京',56,65);

在这里插入图片描述

DROP TABLE emp;
CREATE TABLE emp (
  id INT(11) DEFAULT NULL,
  NAME VARCHAR(20) DEFAULT NULL,
  sex CHAR(1) DEFAULT NULL,
  age INT(11) DEFAULT NULL,
  work_years INT(11) DEFAULT NULL,
  birth DATE DEFAULT NULL,
  salary DOUBLE(8,2) DEFAULT NULL,
  bonus DOUBLE DEFAULT NULL
) ENGINE=INNODB DEFAULT CHARSET=utf8;

/*Data for the table `emp` */

INSERT  INTO `emp`(`id`,`name`,`sex`,`age`,`work_years`,`birth`,`salary`,`bonus`) VALUES 
(1,'三毛','男',18,1,'2021-01-05',1111.00,500),
(2,'二毛','男',19,2,'2021-01-04',2222.00,600),
(3,'大毛','男',20,3,'2021-01-07',3333.00,700),
(4,'大哥','男',21,3,'2021-01-01',4444.00,800),
(5,'二哥','男',22,2,'2021-01-02',5555.00,900),
(6,'三哥','男',23,1,'2021-01-26',6666.00,100),
(7,'三彪子','男',22,5,'2021-01-02',NULL,200),
(8,'张大彪','男',23,4,'2020-12-01',8888.00,300),
(9,'李云龙','男',30,6,'2020-12-02',9999.00,666),
(10,'楚云飞','男',30,4,'2020-12-05',10000.00,555),
(11,'谢宝庆','男',30,5,'2020-12-04',10040.00,NULL),
(NULL,NULL,'男',28,4,'2020-12-03',10045.00,777),
(13,'金毛狮王','男',60,8,'2020-12-06',20020.00,888),
(14,'紫衫龙王','男',61,9,'2020-12-07',20030.00,999),
(15,'青翼蝠王','男',62,8,'2020-12-08',30000.00,100),
(16,'白眉鹰王','男',63,9,'2020-12-09',40000.00,200),
(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(17,'貂蝉','女',63,9,'2020-12-09',2000,200),
(18,'妲己','女',63,9,'2020-12-09',3000,200),
(19,'金莲','女',63,9,'2020-12-09',4000,200);

在这里插入图片描述

  • 练习

    # 按照数学成绩升序排序,如果数学成绩相同,则按照英语成绩降序排序,如果英语成绩相同,则按照语文成绩升序排序。
    select * from stu order by math asc,english desc ,chinese asc;
    
    随堂测试:
    1.将员工表emp的员工按照年龄升序排列,在此条件下,工资降序排列
    
SELECT * FROM emp ORDER BY age ASC ,salary DESC;

2. 聚合函数

  • 理解

    将一列数据作为一个整体,进行纵向的计算
    
  • 语义

    1. count 统计个数
    2. max 求最大值
    3. min 求最小值
    4. sum 求和
    5. avg 求平均值
  • 注意

    1.聚合函数统计时会排序null值,即不统计字段为null 的记录
    2.可以使用ifnull() 解决
    
  • 练习

    1.统计班级共用多少学员
    2.统计数学成绩的最大值
    3.统计英语成绩的最小值
    4.求班级英语成绩总和
    5.求班级英语成绩和数学成绩相加的总和
    6.求班级数学成绩的平均数
    
SELECT COUNT(*)FROM student ;-- 8 1.统计班级共用多少学员
SELECT COUNT(english)FROM student ;-- 7
SELECT COUNT(IFNULL(english,0))FROM student ;-- 8
SELECT MAX(math) FROM student;-- 99  2.统计数学成绩的最大值
SELECT MIN(english) FROM student;-- 65  3.统计英语成绩的最小值
SELECT MIN(IFNULL(english,0)) FROM student;-- 0
SELECT SUM(english) FROM student;-- 570 4.求班级英语成绩总和
SELECT SUM(english)+SUM(math) FROM student;-- 1120  5.求班级英语成绩和数学成绩相加的总和
SELECT AVG(math) FROM student;-- 78.5714 6.求班级数学成绩的平均数
  • 补充

    count(*) 和 count(列名)的区别:
    1.count(*)不会排除null,意为:统计所有的记录数,哪怕某一行所有的列都是null,也会统计在内
    2.count(列名)会排除null,意为:统计某一列不为null的记录数
    3.count(数字)和count(*)等效
    
随堂测试:
  1.查询员工表中工资的平均值
  2.查询员工表中工资大于平均工资的员工的信息
  3.查询员工表中年龄最大的人的信息
  4.查询公司每个月要发多少工资(工资+津贴)
SELECT AVG(salary) FROM emp;--  10630.722  1.查询员工表中工资的平均值
SELECT * FROM emp WHERE salary>(SELECT AVG(salary) FROM emp);-- 2.查询员工表中工资大于平均工资的员工的信息
SELECT * FROM emp WHERE age=(SELECT MAX(age) FROM emp);-- 63  3.查询员工表中年龄最大的人的信息
SELECT SUM(salary)+SUM(bonus) FROM emp;-- 200238  4.查询公司每个月要发多少工资(工资+津贴)
-- 请思考以下两种求和方式有何细致区别:
SELECT SUM(salary)+SUM(bonus) FROM emp 

SELECT SUM(salary+bonus) FROM emp 

/*
结论:
同一行数据,和null值横向相加,结果还是null
同一列数据,和null值纵向相加,null会当作0
*/
-- 正确的方式
SELECT SUM(IFNULL(salary,0)+IFNULL(bonus,0)) FROM emp
-- 或
SELECT SUM(salary)+SUM(bonus) FROM emp 

3. 分组查询

  • 理解分组:统计具有相同特征某一类数据

  • 语法

    group by 字段
    
  • 注意

    1.分组查询中,select后面只能出现 分组的字段和聚合函数,不能出现其它字段,否则没有意义
    
    随堂测试:
    1.查询公司所有女性员工的总工资
    2.查询财务部的平均工资 
    
    注意两点:
    1.相同特征作为分组依据,如:女性,财务部
    2.查询的对象需匹配整个群体的特征,如:总工资,平均工资
    
    请说明如下查询语义是否正确,如不正确该如何更正:
    1.查询公司所有女性员工的年龄
    2.查询财务部的员工姓名
    
SELECT SUM(salary) FROM emp WHERE sex='女';-- 9000 1.查询公司所有女性员工的总工资
SELECT SUM(salary),sex FROM emp GROUP BY sex;

在这里插入图片描述

ALTER TABLE emp ADD dept VARCHAR(20);-- 添加列,并进行修改
UPDATE emp SET dept='财务' WHERE id BETWEEN 1 AND 16;
UPDATE emp SET dept='前台' WHERE id BETWEEN 17 AND 19;
SELECT AVG(salary),dept FROM emp WHERE dept='财务';-- 12307.714286
SELECT AVG(salary),dept FROM emp GROUP BY dept HAVING dept='财务';-- 12307.714286
  • 分组前条件 和 分组后条件 过滤结果集

    • where 分组前条件
    • having 分组后条件
  • 注意:

    1.where 在分组前进行条件过滤,不满足条件的记录不参与分组,不能跟 聚合函数
    2.having 在分组后进行条件限定,不满足限定的记录不会被查询出来, 可以跟 聚合函数
    
  • 案例

    -- 1.按照性别分组,分别查询男女同学的数学平均分,人数
    select sex ,avg(math),count(id) from stu group by sex;
    
    -- 2.按照性别分组,分别查询男女同学的数学平均分,人数;要求分数低于70的人,不参与分组
    select sex ,avg(math),count(id) from stu where math>=70 group by sex;
    
    -- 3.按照性别分组,分别查询男女同学的数学平均分,人数;要求分数低于70的人,不参与分组;分组后的人数要大于2人
    select sex ,avg(math),count(id) from stu where math>=70 group by sex having count(id)>2;
    
    -- 使用别名
    select sex ,avg(math),count(id) 人数 from stu where math>=70 group by sex having 人数>2;
    
    
  • 课堂提问:执行如下 SQL 语句,运行结果是?

    select sex,sum(math) from stu group by sex where sum(math) > 30;
    
    -- 运行错误,group by 后面不能出现 where ,应使用having
    
    随堂测试:
    1.公司决定组织一次海外旅游,只有工资高于3000的员工才能参加,请统计出每个部门的参加人数。
    2.为节省经费,只有可参加人数小于3的部门才能去旅游。
    
SELECT dept,COUNT(id) FROM emp WHERE salary>3000 GROUP BY dept;
SELECT dept,COUNT(id) FROM emp WHERE salary>3000 GROUP BY dept HAVING COUNT(id)<3;

4. 分页查询

  • 引出分页

    数据库中有大量符合搜索条件的数据,但是我们没有必要一次性全部展示,一来查询耗时,二来网络传输耗时,因此我们使用分页展示。
    
  • 语法

    limit offset,size
    -- offset 起始行数,从 0  开始计数,如果省略,默认就是 0
    -- size 每页展示的记录数 
    
  • 案例和公式

    -- 每页展示三条学生记录,查询第一页
    select * from stu limit 0,3
    
    -- 查询第二页
    select * from stu limit 3,3
    
    -- 查询第三页
    select * from stu limit 6,3
    

    公式–找出当前页数起始行数之间的规律

    起始行数 start=(currPage-1)*size
    - currPage 当前页数
    - size 每页展示的记录数
    
    注意:limit 语法是mysql的方言,其它数据库,对于分页有不同的实现方式。
    
随堂测试:
1.查询员工表的第2页数据,每页展示3条数据
SELECT * FROM emp LIMIT 3,3;

二. 约束

  • 概念:

    对表中的数据进行限定,从而保证数据的正确性,有效性,完整性。
    
  • 分类:

    1.主键约束:primary key
    2.非空约束:not null
    3.唯一约束:unique
    4.外键约束:foreign key
    

1. 非空约束

  • 语法

    not null
    
  • 使用

    1.在创建表时添加约束
    
    create table stu(
    	id int,
        name varchar(20) not null
    );
    
    • 删除非空约束

      alter table stu modify name varchar(20);
      
    2.创建表之后,添加约束
    
    alter table stu modify name varchar(20) not null;
    

在这里插入图片描述

2. 唯一约束

  • 语法

    unique -- 某一列的值不能重复
    
  • 使用

    -- 1.创建表时添加唯一约束
    create table stu (
    	id int,
        phone_number varchar(20) unique 
    );
    -- 2.删除唯一约束
    alter table stu modify phone_number varchar(20); -- 错误写法,不会真的删除
    alter table stu drop index phone_number; -- 删除phone_number的索引
    
    -- 3.创建表完成后,添加唯一约束
    alter table stu modify phone_number varchar(20) unique;
    
  • 补充:

    index索引:
    1.一张表的索引可以看成是一本书的目录,添加索引可以提高查找效率。
    2.索引就是一张小表,用于存储某列值的地址值
    3.一张表中索引太多反而会增加查询工作量,延长时间,降低效率
    4.我们可以定义这个索引具有唯一性,所以唯一约束是通过索引index来实现的。
    

    在这里插入图片描述

在这里插入图片描述

3.主键约束

 注意
  1.主键含义:非空 且 唯一
  2.一张表只能有一个字段为主键
  3.主键就是表中记录的唯一标识
  • 补充:

    1.主键是一种特殊的唯一索引
    2.主键列不允许空值,而唯一性索引列允许空值
    
  • 使用

    -- 1.在创建表时添加主键
    create table stu(
    	id int primary key,
        name varchar(20)
    );
    
    -- 2.删除主键
    alter table stu modify id int;-- 错误写法,不会真的删除主键
    alter table stu drop primary key; -- 删除主键,无需指定列,因为一个表只有一个列可以设为主键
    
    -- 3.创建完表后,添加主键
    alter table stu modify id int primary key;
    

在这里插入图片描述
在这里插入图片描述

3.1 主键约束–自增长
  • 概念:如果某一列是数值类型,使用auto_increment 可以完成值的自动增长c
    
  • 使用

    -- 1.创建表时,设置主键自增长,默认从1开始自增长
    create table stu(
    	id int primary key auto_increment,
        name varchar(20)
    );
    
    -- 2.创建表时,设置主键自增长,并指定自增长起始值为6
    create table stu(
    	id int primary key auto_increment,
        name varchar(20)
    )auto_increment=6;
    
    -- 3.删除自增长,不会删除主键
    alter table stu modify id int;
    
    -- 4.创建表完成后,添加自增长
    ALTER TABLE stu MODIFY id INT AUTO_INCREMENT;-- 注意:此次不能再指定主键,因为主键已经存在
    
    -- 5.创建表完成后,设置主键自增长的初始值--前提是表中已经设定过主键自增长
    ALTER TABLE stu AUTO_INCREMENT=100;
    

4. 外键约束

  1. 创建员工部门表,记录员工的详细信息

    -- 创建员工部门表
    create table emp_dept(
    	id int primary key auto_increment,
        name varchar(20) not null,
        age int ,
        dept_name varchar(20),-- 所属公司部门名称
        dept_loc varchar(20) -- 所属公司部门地址
    );
    -- 插入数据
    insert into emp_dept values(null,'张三',18,'研发部','广州');
    insert into emp_dept values(null,'李四',19,'研发部','广州');
    insert into emp_dept values(null,'王五',20,'研发部','广州');
    insert into emp_dept values(null,'大王',21,'销售部','武汉');
    insert into emp_dept values(null,'小王',22,'销售部','武汉');
    insert into emp_dept values(null,'王炸',23,'销售部','武汉');
    
    
  2. 观察数据发现问题:存在数据冗余。解决办法:拆分成两个表

    -- 先删除员工部门表
    drop table emp_dept;
    
    -- 创建部门表
    create table dept (
    	id int primary key auto_increment,
        dept_name varchar(20),
        dept_loc varchar(20)
    );
    
    -- 创建员工表
    create table emp(
    	id int primary key auto_increment,
        name varchar(20) not null,
        age int ,
        dept_id int
    );
    
    -- 插入dept表数据
    insert into dept values(null,'研发部','广州');
    insert into dept values(null,'销售部','武汉');
    
    -- 插入emp表数据
    insert into emp values(null,'张三',18,1);
    insert into emp values(null,'李四',19,1);
    insert into emp values(null,'王五',20,1);
    insert into emp values(null,'大王',21,2);
    insert into emp values(null,'小王',22,2);
    insert into emp values(null,'王炸',23,2);
    
  3. 操作数据发现问题:

    1. 删除部门表数据,会造成员工表中相对应的数据失去意义
    2. 添加新员工时,可以随意填写不存在的部门编号
  • 实际情况:

    1. 公司要解散某个部门,必须先安排好该部门的所有员工
    2. 公司要组建一个新部门,也要先成立部门,再招员工
  • 解决办法:

    • 添加外键约束–关联两个表
    -- 删除员工表
    drop table emp;
    
    -- 重新创建员工表
    create table emp(
    	id int primary key auto_increment,
        name varchar(20) not null,
        age int,
        dept_id int ,
        constraint emp_dept_fk foreign key(dept_id) references dept(id)
    );
    -- 插入emp表数据
    insert into emp values(null,'张三',18,1);
    insert into emp values(null,'李四',19,1);
    insert into emp values(null,'王五',20,1);
    insert into emp values(null,'大王',21,2);
    insert into emp values(null,'小王',22,2);
    insert into emp values(null,'王炸',23,2);
    
  • 删除外键

    alter table emp drop foreign key emp_dept_fk;-- 更改表,删除外键emp_dept_fk
    
  • 创建表之后,添加外键

    alter table emp add constraint emp_dept_fk foreign key (dept_id) references dept(id);
    
4.1 外键约束–级联操作
  • 提出问题:如何将部门表dept中的部门编号1修改为5

    -- 1.先把员工表中的dept_id 修改为 null
    update emp set dept_id =null where dept_id=1;
    
    -- 2.再手动修改部门编号为5
    
    -- 3.将员工表中的dept_id 修改为5
    update emp set dept_id=5 where dept_id is null;
    
  • 有更简单的实现吗?-- 在设置外键时,设置级联操作

    • 查看 架构设计图

    • 级联修改

      -- 先删除外键
      alter table emp drop foreign key emp_dept_fk;-- 更改表,删除外键emp_dept_fk
      
      -- 重新添加外键,并设置级联修改--末尾追加 on update cascade
      alter table emp add constraint emp_dept_fk foreign key (dept_id) references dept(id) on update cascade;
      
      
    • 级联删除

      -- 先删除外键
      alter table emp drop foreign key emp_dept_fk;-- 更改表,删除外键emp_dept_fk
      
      -- 重新添加外键,并设置级联修改和级联删除 
      alter table emp add constraint emp_dept_fk foreign key (dept_id) references dept(id) on update cascade on delete cascade;
      
  • 补充

    1.级联更新和级联删除可以一起使用,也可以单个使用,级联删除需要谨慎使用
    2.级联的理解:单向--> 父表在更新或者删除时,更新或者删除子表对应记录
    

三. 多表关系介绍

  • 数据库设计
    1. 表与表之间的对应关系
      • 一对一
        • 人和身份证
      • 一对多
        • 员工和部门
      • 多对多
        • 学生和课程
    2. 数据库设计的范式

1. 一对多关系实现

在这里插入图片描述

  • 在多的一方建立外键指向一的一方的主键

2. 多对多关系实现

在这里插入图片描述

  • 多对多关系实现需要借助第三方中间表,该表至少包含两个字段。这两个字段作为第三张表的外键,分别指向两张表的主键。

3. 一对一

在这里插入图片描述

  • 一对一关系实现:可以在任意一方添加唯一外键指向另一方的主键

4. 案例

  • 一对多关系案例

    • 需求:一个旅游线路分类中有多个旅游线路
    -- 创建旅游线路分类表 tab_category
    create table tab_category (
    	cid int primary key auto_increment,-- 旅游线路分类主键
    	cname varchar(100) not null unique -- 旅游线路分类名称
    );
    
    -- 插入数据
    insert into tab_category (cname) values 
    ('周边游'), ('出境游'), ('国内游'), ('港澳游');
    
    -- 创建旅游线路表 tab_route
    create table tab_route(
    	rid int primary key auto_increment, -- 旅游线路主键
    	rname varchar(100) not null unique,-- 旅游线路名称
    	price double, -- 价格
    	rdate date, -- 上架时间
    	cid int, -- cid 外键
    	foreign key (cid) references tab_category(cid)
    );
    
    -- 添加旅游线路数据
    INSERT INTO tab_route VALUES
    (NULL, '【厦门+鼓浪屿+南普陀寺+曾厝垵 高铁 3 天 惠贵团】尝味友鸭面线 住 1 晚鼓浪屿', 1499,
    '2018-01-27', 1),
    (NULL, '【浪漫桂林 阳朔西街高铁 3 天纯玩 高级团】城徽象鼻山 兴坪漓江 西山公园', 699, '2018-02-
    22', 3),
    (NULL, '【爆款¥1699 秒杀】泰国 曼谷 芭堤雅 金沙岛 杜拉拉水上市场 双飞六天【含送签费 泰风情 广州
    往返 特价团】', 1699, '2018-01-27', 2),
    (NULL, '【经典•狮航 ¥2399 秒杀】巴厘岛双飞五天 抵玩【广州往返 特价团】', 2399, '2017-12-23',
    2),
    (NULL, '香港迪士尼乐园自由行 2 天【永东跨境巴士广东至迪士尼去程交通+迪士尼一日门票+香港如心海景酒店
    暨会议中心标准房 1 晚住宿】', 799, '2018-04-10', 4);
    
  • 多对多关系案例

    -- 创建用户表 tab_user
    create table tab_user (
    	uid int primary key auto_increment,--  主键
    	username varchar(100) unique not null,-- 用户名
    	password varchar(30) not null,-- 密码
    	name varchar(100),-- 用户姓名
    	birthday date,-- 生日
    	sex char(1) default '男',-- 性别
    	telephone varchar(11),-- 手机
    	email varchar(100)-- 邮箱
    );
    -- 添加用户数据
    INSERT INTO tab_user VALUES
    (NULL, 'cz110', 123456, '老王', '1977-07-07', '男', '13888888888', '66666@qq.com'),
    (NULL, 'cz119', 654321, '小王', '1999-09-09', '男', '13999999999', '99999@qq.com');
    
    
    -- 创建收藏表 tab_favorite
    create table tab_favorite (
    	rid int,
    	date datetime,
    	uid int,
    	primary key(rid,uid),-- 创建复合主键
    	foreign key (rid) references tab_route(rid),
    	foreign key(uid) references tab_user(uid)
    );
    -- 增加收藏表数据
    INSERT INTO tab_favorite VALUES
    (1, '2018-01-01', 1), -- 老王选择厦门
    (2, '2018-02-11', 1), -- 老王选择桂林
    (3, '2018-03-21', 1), -- 老王选择泰国
    (2, '2018-04-21', 2), -- 小王选择桂林
    (3, '2018-05-08', 2), -- 小王选择泰国
    (5, '2018-06-02', 2); -- 小王选择迪士尼
    

四. 范式

1. 概述
1.什么是范式:
	制定一些规则来优化数据的设计和存储,这些规则就称为范式。
2.三大范式:
	目前关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)
满足最低要求的范式是第一范式(1NF)。在第一范式的基础上进一步满足更多规范要求的称为第二范式(2NF) ,其余范式以次类推。一般说来,数据库只需满足第三范式(3NF)就行了。

1NF:
	第一范式每一列不可再拆分,称为原子性。
2NF:
	第二范式就是在第一范式的基础上所有列完全依赖于主键列。
当存在一个复合主键包含多个主键列的时候,才会发生不符合第二范式的情况。
比如有一个主键有两个列,不能存在这样的属性,它只依赖于其中一个列,这就是不符合第二范式。

    第二范式的特点:
    1)  一张表只描述一件事情。
    2)  表中的每一列都完全依赖于主键

3NF:
	第三范式就是所有列不依赖于其它非主键列,也就是在满足 2NF 的基础上,任何非主列不得传递依赖于主键。
2. 三大范式详解
  • 创建最开始的表

    -- 创建学员相关信息表
    create table stu(
    	id varchar(10),
        name varchar(10),
        major varchar(20),-- 系名和系主任
        course varchar(20),-- 课程
        score int -- 分数
    );
    -- 插入数据
    insert into stu values
    ('10010','张无忌','经济系 张三丰','高等数学',95),
    ('10010','张无忌','经济系 张三丰','大学英语',87),
    ('10010','张无忌','经济系 张三丰','计算机基础',65),
    ('10011','令狐冲','法律系 任我行','法理学',77),
    ('10011','令狐冲','法律系 任我行','大学英语',87),
    ('10011','令狐冲','法律系 任我行','法律社会学',65),
    ('10012','杨过','经济系 张三丰','法律社会学',95),
    ('10012','杨过','经济系 张三丰','法理学',97),
    ('10012','杨过','经济系 张三丰','大学英语',99);
    
    
    这样建表存在的问题:
    1.如果更改系主任,需要更改整个系的信息,数据没有独立
    2.存在大量数据冗余
    3.新增一个系的信息时,其它字段数据为空,造成数据不完整
    4.学员毕业,删除一个学员信息时,会连带删除系的信息
    
  • 使用第一范式,优化表结构

    -- 删除表 
    drop table stu;
    
    -- 创建学员相关信息表,拆分系名和系主任为两个字段
    create table stu(
    	id varchar(10),
        name varchar(10),
        major_name varchar(20),-- 系名
        major_monitor varchar(20),-- 系主任
        course varchar(20),-- 课程名
        score int -- 分数
    );
    -- 插入数据
    insert into stu values
    ('10010','张无忌','经济系','张三丰','高等数学',95),
    ('10010','张无忌','经济系','张三丰','大学英语',87),
    ('10010','张无忌','经济系','张三丰','计算机基础',65),
    ('10011','令狐冲','法律系','任我行','法理学',77),
    ('10011','令狐冲','法律系','任我行','大学英语',87),
    ('10011','令狐冲','法律系','任我行','法律社会学',65),
    ('10012','杨过','经济系','张三丰','法律社会学',95),
    ('10012','杨过','经济系','张三丰','法理学',97),
    ('10012','杨过','经济系','张三丰','大学英语',99);
    
  • 存在非完全依赖

    • 分数的唯一确定,需要依赖学号课程,所以,如果以学号课程作为核心字段的话,我们发现姓名系名以及系主任的确定,只跟学号有关,和课程无关,这就说明存在非完全依赖
  • 按照第二范式优化表结构,去除非完全依赖

    -- 拆分为 学员 和 考试成绩 两个表
    create table stu(
    	id varchar(10),-- 学员编号
        name varchar(20), -- 学员姓名
        major_name varchar(20), -- 系名
        major_monitor varchar(20) -- 系主任
    );
    
    create table exam(
    	id varchar(10),-- 学员编号
        course varchar(10),-- 课程名
        score int -- 分数    
    );
    
    -- 插入数据
    insert into stu values
    ('10010','张无忌','经济系','张三丰'),
    ('10010','张无忌','经济系','张三丰'),
    ('10010','张无忌','经济系','张三丰'),
    ('10011','令狐冲','法律系','任我行'),
    ('10011','令狐冲','法律系','任我行'),
    ('10011','令狐冲','法律系','任我行'),
    ('10012','杨过','经济系','张三丰'),
    ('10012','杨过','经济系','张三丰'),
    ('10012','杨过','经济系','张三丰');
    
    insert into exam values
    ('10010','高等数学',95),
    ('10010','大学英语',87),
    ('10010','计算机基础',65),
    ('10011','法理学',77),
    ('10011','大学英语',87),
    ('10011','法律社会学',65),
    ('10012','法律社会学',95),
    ('10012','法理学',97),
    ('10012','大学英语',99);
    
  • 观察数据发现,学员表中存在传递依赖

    • 学员姓名可以确定系名系名可以确定系主任学员姓名也可以直接确定系主任,此关系为传递依赖
    • 存在传递依赖,说明表结构还不够单一化,还不够简洁,并且还存在数据冗余
  • 按照第三范式的要求,消除传递依赖,进一步优化表结构,继续拆分表

    -- 先删除学员表 
    drop table stu;
    
    -- 拆分学员表为 学员表和系表
    create table stu(
    	id varchar(10) primary key,-- 学员编号 此时方可添加主键
        name varchar(20) -- 学员姓名 
    );
    
    create table major(
    	major_name varchar(20) primary key, -- 系名
        major_monitor varchar(20) -- 系主任
    );
    
    -- 插入数据
    insert into stu values
    ('10010','张无忌'),
    ('10011','令狐冲'),
    ('10012','杨过');
    
    insert into major values
    ('经济系','张三丰'),
    ('法律系','任我行');
    
    
  • 总结:

    范式特点
    1NF原子性:表中每列不可再拆分。
    2NF不产生局部依赖,一张表只描述一件事情
    3NF不产生传递依赖,表中每一列都直接依赖于主键。而不是通过其它列间接依赖于主键。
    设计范式的目的:
    1.使结构更合理,使数据冗余尽量小。便于插入、删除和更新
    2.遵从概念单一化“一事一地”原则,即一个关系模式描述一个实体或实体间的一种联系。
    3.范式的实质就是概念的单一化
    

五. 数据库的备份和还原

  • 命令行操作

    -- 备份
    mysqldump -u用户名 -p密码 备份的数据库名 > 保存的sql文件路径
    -- 练习:备份数据库db1
    mysqldump -uroot -proot db1 > f:/a.sql
    
    -- 还原 ,需要登录后操作
    -- 1.创建数据库
    create database db1;
    -- 2.使用数据库
    use  db1;
    -- 3.导入sql文件
    source  f:/a.sql;
    

步骤:
win+R cmd
– 备份
在这里插入图片描述

– 还原 ,需要登录后操作
在这里插入图片描述

– 1.创建数据库
在这里插入图片描述

– 2.使用数据库
– 3.导入sql文件
在这里插入图片描述

  • 可视化工具操作
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值