当前位置: 首页 > news >正文

MySQL 学习笔记(基础篇 Day3)

「写在前面」

本文为黑马程序员 MySQL 教程的学习笔记。本着自己学习、分享他人的态度,分享学习笔记,希望能对大家有所帮助。推荐先按顺序阅读往期内容:
1. MySQL 学习笔记(基础篇 Day1)
2. MySQL 学习笔记(基础篇 Day2)


目录

  • 5 多表查询
    • 5.1 多表关系
    • 5.2 多表查询概述
    • 5.3 内连接
    • 5.4 外连接
    • 5.5 自连接
    • 5.6 子查询
    • 5.7 多表查询案例
  • 6 事务
    • 6.1 事务简介
    • 6.2 事务操作
    • 6.3 事务四大特性
    • 6.4 并发事务问题
    • 6.5 事务隔离级别

5 多表查询

5.1 多表关系

P37:https://www.bilibili.com/video/BV1Kr4y1i7ru?p=37

项目开发中,在进行数据库表结构设计时,会根据业务需求及业务模块之间的关系,分析并设计表结构,由于业务之间相互关联,所以各个表结构之间也存在着各种联系,基本上分为三种:

  • 一对多(多对一)
  • 多对多
  • 一对一
5.1.1 一对多
  • 案例: 部门 与 员工的关系
  • 关系: 一个部门对应多个员工,一个员工对应一个部门
  • 实现: 在多的一方建立外键,指向一的一方的主键
alt
5.1.2 多对多
  • 案例: 学生 与 课程的关系
  • 关系: 一个学生可以选修多门课程,一门课程也可以供多个学生选择
  • 实现: 建立第三张中间表,中间表至少包含两个外键,分别关联两方主键
alt

对应的SQL脚本:

# 创建 student 表
create table student(
id int auto_increment primary key comment '主键ID',
name varchar(10) comment '姓名',
no varchar(10) comment '学号'
) comment '学生表';
# 向 student 表中插入数据
insert into student values (null, '黛绮丝', '2000100101'),(null, '谢逊', '2000100102'),(null, '殷天正', '2000100103'),(null, '韦一笑', '2000100104');

# 创建 course 表
create table course(
id int auto_increment primary key comment '主键ID',
name varchar(10) comment '课程名称'
) comment '课程表';
# 向 course 表中插入数据
insert into course values (null, 'Java'), (null, 'PHP'), (null , 'MySQL') ,(null, 'Hadoop');

# 创建 student_course 中间表
create table student_course(
id int auto_increment comment '主键' primary key,
studentid int not null comment '学生ID',
courseid int not null comment '课程ID',
constraint fk_courseid foreign key (courseid) references course (id),
constraint fk_studentid foreign key (studentid) references student (id)
) comment '学生课程中间表';
# 插入数据关联两方主键
insert into student_course values (null,1,1),(null,1,2),(null,1,3),(null,2,2),(null,2,3),(null,3,4);
5.1.3 一对一
  • 案例: 用户 与 用户详情的关系
  • 关系: 一对一关系,多用于单表拆分,将一张表的基础字段放在一张表中,其他详情字段放在另一张表中,以提升操作效率
  • 实现: 在任意一方加入外键,关联另外一方的主键,并且设置外键为唯一的(UNIQUE)
alt

5.2 多表查询概述

P38:https://www.bilibili.com/video/BV1Kr4y1i7ru?p=38

多表查询就是指从多张表中查询数据。

原来查询单表数据,执行的SQL形式为:

select * from emp;

而在多表查询中,我们是需要消除无效的笛卡尔积的,只保留两张表关联部分的数据:

select * from emp , dept where emp.dept_id = dept.id;

多表查询分类:

  • 连接查询
    • 内连接:相当于查询A、B交集部分数据
    • 外连接:
      • 左外连接:查询左表所有数据,以及两张表交集部分数据
      • 右外连接:查询右表所有数据,以及两张表交集部分数据
    • 自连接:当前表与自身的连接查询,自连接必须使用表别名
  • 子查询
alt

5.3 内连接

P39:https://www.bilibili.com/video/BV1Kr4y1i7ru?p=39

内连接查询的是两张表交集部分的数据

1. 隐式内连接

SELECT 字段列表 FROM1 , 表2 WHERE 条件 ... ;

2. 显式内连接

SELECT 字段列表 FROM1 [ INNER ] JOIN2 ON 连接条件 ... ;

案例:

# A. 查询每一个员工的姓名 , 及关联的部门的名称 (隐式内连接实现)
select emp.name , dept.name from emp , dept where emp.dept_id = dept.id ;

# B. 查询每一个员工的姓名 , 及关联的部门的名称 (显式内连接实现)
select e.name, d.name from emp e inner join dept d on e.dept_id = d.id;

5.4 外连接

P40:https://www.bilibili.com/video/BV1Kr4y1i7ru?p=40

1. 左外连接

左外连接相当于查询表1(左表)的所有数据,当然也包含表1和表2交集部分的数据。

SELECT 字段列表 FROM1 LEFT [ OUTER ] JOIN2 ON 条件 ... ;

2. 右外连接

右外连接相当于查询表2(右表)的所有数据,当然也包含表1和表2交集部分的数据。

SELECT 字段列表 FROM1 RIGHT [ OUTER ] JOIN2 ON 条件 ... ;

案例:

# A. 查询emp表的所有数据, 和对应的部门信息
select e.*, d.name from emp e left outer join dept d on e.dept_id = d.id;

# B. 查询dept表的所有数据, 和对应的员工信息(右外连接)
select d.*, e.* from emp e right outer join dept d on e.dept_id = d.id;

5.5 自连接

5.5.1 自连接查询

P41:https://www.bilibili.com/video/BV1Kr4y1i7ru?p=41

自连接查询,顾名思义,就是自己连接自己,也就是把一张表连接查询多次。

自连接的查询语法:

SELECT 字段列表 FROM 表A 别名A JOIN 表A 别名B ON 条件 ... ;

案例:

# A. 查询员工 及其 所属领导的名字
select a.name , b.name from emp a , emp b where a.managerid = b.id;

# B. 查询所有员工 emp 及其领导的名字 emp , 如果员工没有领导, 也需要查询出来
select a.name '员工', b.name '领导' from emp a left join emp b on a.managerid = b.id;

注意事项:在自连接查询中,必须要为表起别名,要不然我们不清楚所指定的条件、返回的字段,到底是哪一张表的字段。

5.5.2 联合查询

P42:https://www.bilibili.com/video/BV1Kr4y1i7ru?p=42

对于union查询,就是把多次查询的结果合并起来,形成一个新的查询结果集。

语法:

SELECT 字段列表 FROM 表A ...
UNION [ ALL ]
SELECT 字段列表 FROM 表B ....;
  • 对于联合查询的多张表的列数必须保持一致,字段类型也需要保持一致。
  • union all 会将全部的数据直接合并在一起,union 会对合并之后的数据去重。

案例:

# A. 将薪资低于 5000 的员工 , 和 年龄大于 50 岁的员工全部查询出来
select * from emp where salary < 5000
union
select * from emp where age > 50;

union 联合查询,会对查询出来的结果进行去重处理。

注意:如果多条查询语句查询出来的结果,字段数量不一致,在进行union/union all联合查询时,将会报错。

5.6 子查询

5.6.1 概述

P43:https://www.bilibili.com/video/BV1Kr4y1i7ru?p=43

1. 概念

SQL语句中嵌套SELECT语句,称为嵌套查询,又称子查询。

SELECT * FROM t1 WHERE column1 = ( SELECT column1 FROM t2 );

子查询外部的语句可以是INSERT / UPDATE / DELETE / SELECT 的任何一个

2. 分类

根据子查询结果不同,分为:
A. 标量子查询(子查询结果为单个值)
B. 列子查询(子查询结果为一列)
C. 行子查询(子查询结果为一行)
D. 表子查询(子查询结果为多行多列)

根据子查询位置,分为:
A. WHERE之后
B. FROM之后
C. SELECT之后

5.6.2 标量子查询

P44:https://www.bilibili.com/video/BV1Kr4y1i7ru?p=44

子查询返回的结果是单个值(数字、字符串、日期等),最简单的形式,这种子查询称为标量子查询。

常用的操作符:= <> > >= < <=

案例:

# A. 查询 "销售部" 的所有员工信息
select * from emp where dept_id = (select id from dept where name = '销售部');

# B. 查询在 "方东白" 入职之后的员工信息
select * from emp where entrydate > (select entrydate from emp where name = '方东白');
5.6.3 列子查询

P45:https://www.bilibili.com/video/BV1Kr4y1i7ru?p=45

子查询返回的结果是一列(可以是多行),这种子查询称为列子查询。

常用的操作符:IN 、NOT IN 、 ANY 、SOME 、 ALL

操作符描述
IN在指定的集合范围之内,多选一
NOTIN 不在指定的集合范围之内
ANY子查询返回列表中,有任意一个满足即可
SOME与ANY等同,使用SOME的地方都可以使用ANY
ALL子查询返回列表的所有值都必须满足

案例:

# A. 查询 "销售部" 和 "市场部" 的所有员工信息
select * from emp where dept_id in (select id from dept where name = '销售部' or name = '市场部');

# B. 查询比 财务部 所有人工资都高的员工信息
select * from emp where salary > all ( select salary from emp where dept_id = (select id from dept where name = '财务部') );

# C. 查询比研发部其中任意一人工资高的员工信息
select * from emp where salary > any ( select salary from emp where dept_id = (select id from dept where name = '研发部') );
5.6.4 行子查询

P46:https://www.bilibili.com/video/BV1Kr4y1i7ru?p=46

子查询返回的结果是一行(可以是多列),这种子查询称为行子查询。

常用的操作符:= 、<> 、IN 、NOT IN

案例:

# A. 查询与 "张无忌" 的薪资及直属领导相同的员工信息 ;
select * from emp where (salary,managerid) = (select salary, managerid from emp where name = '张无忌');
5.6.5 表子查询

P47:https://www.bilibili.com/video/BV1Kr4y1i7ru?p=47

子查询返回的结果是多行多列,这种子查询称为表子查询。

常用的操作符:IN

案例:

# A. 查询与 "鹿杖客" , "宋远桥" 的职位和薪资相同的员工信息
select * from emp where (job,salary) in ( select job, salary from emp where name = '鹿杖客' or name = '宋远桥' );

# B. 查询入职日期是 "2006-01-01" 之后的员工信息 , 及其部门信息
select e.*, d.* from (select * from emp where entrydate > '2006-01-01') e left join dept d on e.dept_id = d.id ;

5.7 多表查询案例

P48:https://www.bilibili.com/video/BV1Kr4y1i7ru?p=48

P49:https://www.bilibili.com/video/BV1Kr4y1i7ru?p=49

P50:https://www.bilibili.com/video/BV1Kr4y1i7ru?p=50

6 事务

6.1 事务简介

P51:https://www.bilibili.com/video/BV1Kr4y1i7ru?p=51

事务是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败

就比如: 张三给李四转账 1000 块钱,张三银行账户的钱减少 1000,而李四银行账户的钱要增加 1000。这一组操作就必须在一个事务的范围内,要么都成功,要么都失败。

注意: 默认MySQL的事务是自动提交的,也就是说,当执行完一条DML语句时,MySQL会立即隐式的提交事务。

6.2 事务操作

P52:https://www.bilibili.com/video/BV1Kr4y1i7ru?p=52

数据准备:

drop table if exists account;

create table account(
id int primary key AUTO_INCREMENT comment 'ID',
name varchar(10) comment '姓名',
money double(10,2) comment '余额'
) comment '账户表';

insert into account(name, money) VALUES ('张三',2000), ('李四',2000);
6.2.1 未控制事务

1. 测试正常情况

-- 1. 查询张三余额
select * from account where name = '张三';
-- 2. 张三的余额减少1000
update account set money = money - 1000 where name = '张三';
-- 3. 李四的余额增加1000
update account set money = money + 1000 where name = '李四';

测试完毕之后检查数据的状态, 可以看到数据操作前后是一致的

alt

2. 测试异常情况

-- 1. 查询张三余额
select * from account where name = '张三';
-- 2. 张三的余额减少1000
update account set money = money - 1000 where name = '张三';
出错了....
-- 3. 李四的余额增加1000
update account set money = money + 1000 where name = '李四';

我们把数据都恢复到2000, 然后再次一次性执行上述的SQL语句(出错了.... 这句话不符合SQL语法,执行就会报错),检查最终的数据情况, 发现数据在操作前后不一致了

alt
6.2.2 控制事务一

1. 查看/设置事务提交方式

SELECT @@autocommit ;
SET @@autocommit = 0 ;

2. 提交事务

COMMIT;

3. 回滚事务

ROLLBACK;

注意:上述的这种方式,我们是修改了事务的自动提交行为, 把默认的自动提交修改为了手动提交, 此时我们执行的DML语句都不会提交, 需要手动的执行commit进行提交。

6.2.3 控制事务二

1. 开启事务

START TRANSACTIONBEGIN ;

2. 提交事务

COMMIT;

3. 回滚事务

ROLLBACK;

转账案例:

-- 开启事务
start transaction
-- 1. 查询张三余额
select * from account where name = '张三';
-- 2. 张三的余额减少1000
update account set money = money - 1000 where name = '张三';
-- 3. 李四的余额增加1000
update account set money = money + 1000 where name = '李四';
-- 如果正常执行完毕, 则提交事务
commit;
-- 如果执行过程中报错, 则回滚事务
-- rollback;

6.3 事务四大特性

P53:https://www.bilibili.com/video/BV1Kr4y1i7ru?p=53

  • 原子性(Atomicity):事务是不可分割的最小操作单元,要么全部成功,要么全部失败。
  • 一致性(Consistency):事务完成时,必须使所有的数据都保持一致状态。
  • 隔离性(Isolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。
  • 持久性(Durability):事务一旦提交或回滚,它对数据库中的数据的改变就是永久的。

上述就是事务的四大特性,简称ACID。

alt

6.4 并发事务问题

P54:https://www.bilibili.com/video/BV1Kr4y1i7ru?p=54

1. 赃读

一个事务读到另外一个事务还没有提交的数据。

alt

比如B读取到了A未提交的数据

2. 不可重复读

一个事务先后读取同一条记录,但两次读取的数据不同,称之为不可重复读

alt

事务A两次读取同一条记录,但是读取到的数据却是不一样的

3. 幻读

一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在,好像出现了 "幻影"

alt

6.5 事务隔离级别

P55:https://www.bilibili.com/video/BV1Kr4y1i7ru?p=55

为了解决并发事务所引发的问题,在数据库中引入了事务隔离级别。主要有以下几种:

隔离级别脏读不可重复读幻读
Read uncommitted
Read committed×
Repeatable Read(默认)××
Serializable×××

1. 查看事务隔离级别

SELECT @@TRANSACTION_ISOLATION;

2. 设置事务隔离级别

SET [ SESSION | GLOBAL ] TRANSACTION ISOLATION LEVEL { READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE }

注意:事务隔离级别越高,数据越安全,但是性能越低。

事物小结

P56:https://www.bilibili.com/video/BV1Kr4y1i7ru?p=56

基础篇总结

P57:https://www.bilibili.com/video/BV1Kr4y1i7ru?p=57


「结束」

注:本文为个人学习笔记,仅供大家参考学习,不得用于任何商业目的。如有侵权,请联系作者删除。

alt

本文由 mdnice 多平台发布

相关文章:

  • qt练习案例
  • Visual studio编译器报1个无法解析的外部命令
  • Linux下阻塞IO驱动实验实例二
  • 软考网络工程师 第五章 第一节 移动通信与5G
  • 每日一练:LeeCode-35、搜索插入位置【数组】、面试题 01.08. 零矩阵【数组】、面试题 01.07. 旋转矩阵【数组+行列翻转】
  • 【Spring云原生系列】SpringBoot+Spring Cloud Stream:消息驱动架构(MDA)解析,实现异步处理与解耦合
  • 5分钟,我把网站性能优化了3倍
  • C++程序设计-第六/七/八章 运算符重载/包含与继承/虚函数和多态性【期末复习|考研复习】
  • 【AI视野·今日NLP 自然语言处理论文速览 第八十三期】Wed, 6 Mar 2024
  • 大语言模型中,role为user、assistant、system有什么区别
  • Django工具
  • 微信小程序如何实现下拉刷新
  • 备战蓝桥杯---动态规划的一些思想2
  • Rust 语言中的泛型
  • 数学建模-敏感度分析(美赛)
  • 学习笔记。。。
  • 【自然语言处理】BitNet b1.58:1bit LLM时代
  • 如何在小程序中绑定身份证
  • 【深圳五兴科技】Java后端面经
  • Spring MVC 全局异常处理器
  • 紧盯大V、网红带货肉制品,整治制售假劣肉制品专项行动开展
  • 中方对中美就关税谈判的立场发生变化?外交部:中方立场没有任何改变
  • 深圳一购房者交首付后迟迟无法签合同,澎湃介入后开发商承诺退款
  • 观察|“离境退税”撬动上海“五一”假期入境消费
  • “五一”假期预计全社会跨区域人员流动累计14.67亿人次
  • 巴菲特第60次股东大会开场点赞库克:他为伯克希尔赚的钱比我还多