131.【MySQL_基础篇】(四)

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 131.【MySQL_基础篇】

(五)、多表查询

1.多表关系

(1).多表查询概述

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

  1. 一对一
  2. 多对多
  3. 一对多(多对一)
(2).一对多 (多对一)关系

这种关系最典型的列子就是 员工和部门的关系。员工为N 部门为1。

这种我们通常在从表(员工表)也就是员工表创建一个外键,与主表(部门表)进行联系。

(3).多对多关系

这种关系最典型的列子就是 学生与课程的关系。一个学生可以选择多门课程,一门课程可以供多各学生选择。

这种我们需要建立第三张表(中间表)并包括两个外键,第一个外键需要与学生表进行关联,另一张表需要和课程表进行关联。

建立 学生表+课程表+中间表

create table student(
    id int auto_increment primary key comment '主键ID',
    name varchar(10) comment '姓名',
    no varchar(10) comment '学号'
) comment '学生表' charset=utf8;
insert into student values (null, '黛绮丝', '2000100101'),(null, '谢逊','2000100102'),(null, '殷天正', '2000100103'),(null, '韦一笑', '2000100104') ;
create table course(
    id int auto_increment primary key comment '主键ID',
    name varchar(10) comment '课程名称'
) comment '课程表' charset=utf8;
insert into course values (null, 'Java'), (null, 'PHP'), (null , 'MySQL') ,(null, 'Hadoop');
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 '学生课程中间表' charset=utf8;
insert into student_course values (null,1,1),(null,1,2),(null,1,3),(null,2,2),(null,2,3);
(4)一对一关系

这种关系最典型的列子就是 用户与用户详情的关系。

一对一关系,多用于单表拆分,将一张表的基础字段放在一张表中,其他详情字段放在另一张表中,以提升操作效率。

这种关系我们需要在 任意一方假如外键,关联另外一方的主键,并且设置外键为唯一的(unique)

create table tb_user(
id int auto_increment primary key comment '主键ID',
name varchar(10) comment '姓名',
age int comment '年龄',
gender char(1) comment '1: 男 , 2: 女',
phone char(11) comment '手机号'
) comment '用户基本信息表';
create table tb_user_edu(
id int auto_increment primary key comment '主键ID',
degree varchar(20) comment '学历',
major varchar(50) comment '专业',
primaryschool varchar(50) comment '小学',
middleschool varchar(50) comment '中学',
university varchar(50) comment '大学',
userid int unique comment '用户ID',
constraint fk_userid foreign key (userid) references tb_user(id)
) comment '用户教育信息表';
insert into tb_user(id, name, age, gender, phone) values
(null,'黄渤',45,'1','18800001111'),
(null,'冰冰',35,'2','18800002222'),
(null,'码云',55,'1','18800008888'),
(null,'李彦宏',50,'1','18800009999');
insert into tb_user_edu(id, degree, major, primaryschool, middleschool,
university, userid) values
(null,'本科','舞蹈','静安区第一小学','静安区第一中学','北京舞蹈学院',1),
(null,'硕士','表演','朝阳区第一小学','朝阳区第一中学','北京电影学院',2),
(null,'本科','英语','杭州市第一小学','杭州市第一中学','杭州师范大学',3),
(null,'本科','应用数学','阳泉第一小学','阳泉区第一中学','清华大学',4);

2.多表查询概述

(1).笛卡尔积效应

笛卡尔积时指在数学中,两个集合A集合和B集合的所有组合情况(排列组合)。(在多表查询时,需要消除无效的笛卡尔积)

-- 多表查询,会发现出现笛卡尔积效应
select *from emp,dept;

(2).消除笛卡尔积效应

消除笛卡尔积效应的实质就是 消除掉不符合条件的排列组合数据。

-- 消除无效的笛卡尔积
select *from emp,dept where emp.dept_id=dept.id;

3.多表查询分类

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

概念:SQL语句中嵌套Select语句,称为嵌套查询,又称子查询。

select *from 表1 where column1=(select column1 from 表2)

子查询外部的语句可以是 insert/update/delete/select的任何一个。

4.连接查询-内连接 (两张表交集部分) ⭐

(1).隐式内连接语法
selec 字段列表 from 表1,表2 where 条件...
(2).显示内连接语法
select 字段列表 from 表1 [inner] join 表2 on 连接条件...;
(3).隐式内连接和显示内联接测试
  1. 隐式内连接 查询部门员工和对应部门
-- 隐式内连接使用where进行判断
select emp.`name`,dept.name  from emp,dept on emp.dept_id=dept.id;
-- 隐式内连接起别名,起玩别名之后只能用别名操作了
select ep.`name`,dt.name  from emp as ep,dept as dt on ep.dept_id=dt.id;

  1. 显示内连接查询部门员工
-- 显示内连接
select emp.`name`,dept.name from emp inner join dept where emp.dept_id=dept.id;
-- 显示内连接 可省略inner
select emp.`name`,dept.name from emp inner join dept where emp.dept_id=dept.id;

5.连接查询-外连接 (查询某张表的全部数据和交集部分)

相当于查询 left 或 right 左侧的第一个表的全部数据。

(1).外连接查询语法
  1. 左外连接

这里相当于查询表1 的所有数据和表一与表二的交集

select 字段列表 from 表1 left [outer] join 表2 on 条件;
  1. 右外连接

这里相当于查询表2 的所有数据和表一与表二的交集

select 字段列表 from 表1 right [outer] join 表2 on 条件;
(2).左外连接测试

关键字 left

-- 左外连接演示
-- 1.查询emp表的所有数据,和对应的部门信息(左外连接)
select * from emp left join dept on emp.dept_id=dept.id;
-- 2.查询emp表的所有数据,和对应的部门信息(左外连接) 起别名
select *from emp as ep left join dept as dt on ep.dept_id=dt.id; 

(3).右外连接测试

关键字 right

-- 1.查询dept表的所有数据,和对应的员工信息
select dept.*,emp.`name` from emp right join dept on emp.dept_id=dept.id;

6.连接查询-自连接 (可交集、可单独) ⭐

子连接查询语法,一定要给表起别名。

(1).自连接查询语法
select 字段列表 from 表A 别名A join 表A 别名B on 条件...;

自连接查询,可以是内连接查询,也可以是外连接查询。

(2).自连接测试
  1. 查询员工 及其 所属领导的名字

不管是什么连接都是经历了 排列组合 实现的数据查询

-- 自连接
-- 1.查询员工 及其 所属领导的名字, 这里的ep_1相当于员工表,ep_2相当于领导表。 利用员工表的领导id 找 员工表的id
select ep_1.`name`,ep_2.`name` from emp ep_1 join emp ep_2 on ep_1.managerid=ep_2.id;

  1. 查询所有员工 emp 及其 领导的名字emp,如果员工没有领导,也需要查询出来。
-- 查询所有员工 emp 及其 领导的名字emp,如果员工没有领导,也需要查询出来
select ep_1.`name`,ep_2.`name` from emp ep_1 left join emp ep_2 on ep_1.managerid=ep_2.id;

7.联合查询-union,union all

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

(1).联合查询的语法
select 字段列表 from 表A...
union [all]
select 字段列表 from 表B...
(2).联合查询示列
  1. 查询出所有满足的->不去重
-- 将薪资低于5000的员工,和年龄大于50岁的员工全部查询出来
select *from emp WHERE salary<5000 
union all #⭐
select *from emp WHERE age>50;

  1. 查询出所有满足的->去重
-- 将薪资低于5000的员工,和年龄大于50岁的员工全部查询出来  (去重)
select *from emp WHERE salary<5000 
union   # ⭐
select *from emp WHERE age>50;

注意:

  1. 对于联合查询的多张表的列数必须保持一致,字段类型也需要保持一致。
  2. union all会将全部的数据直接合并在一起,union会对合并之后的数据进行去重的操作。

8.子查询 (嵌套查询) ⭐

(1).子查询的基本语法

概念:SQL语句中嵌套Select语句,称为嵌套查询,又称子查询。

select *from 表1 where column1=(select column1 from 表2)
• 1

子查询外部的语句可以是 insert/update/delete/select的任何一个。

(2).子查询的分类

根据子查询结果不同,分为:

  1. 标量子查询(子查询结果为单个值)
  2. 列子查询(子查询结果为一列)
  3. 行字查询(子查询结果为一行)
  4. 表子查询(子查询结果为多行多列)

根据子查询位置,分为:where之后、from之后、select之后。

9.子查询-标量子查询 (返回结果是一个值)

(1).标量子查询

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

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

(2).标量子查询示列

1..查询销售部的所有员工

-- 标量子查询
-- 1.查询销售部的所有员工信息
    -- 1.1先查找销售部的id
select  id from dept where `name`='销售部'
    -- 1.2再查找这个数据
select *from emp where emp.dept_id=4;
-- 完整写法
select *from emp where emp.dept_id= (select  id from dept where `name`='销售部');

2.查询在房东白入职之后的员工信息

-- 查询在方东白入职之后的员工信息
select entrydate from emp where name ='方东白';
select *from emp where entrydate>'2009-02-12';
-- 完整写法
select *from emp where entrydate>(select entrydate from emp where name ='方东白');

10.子查询-列子查询 (单列但可多行)

返回结构是一列数据 比如: 所有查询所有员工的id。 也就是一行数据里面的一个字段,但是可以是多行的同一字段。

(1).列子查询

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

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

  1. IN : 在指定的集合范围之内,多选一。
  2. NOT IN: 不在指定的集合范围之内。
  3. ANY: 子查询返回列表,有任意一个满足即可。
  4. SOME: 与ANY等同,使用SOME的地方都可以使用ANY。
  5. ALL:子查询返回列表的所有值都必须满足。
(2).列子查询示列

1.查询销售部和市场部的所有员工

-- 列子查询
-- 1.查询销售部和市场部的所有员工
select id from dept where dept.`name` in ('市场部','销售部');
select *from emp where emp.dept_id in (2,4);
select *from emp where emp.dept_id in (select id from dept where dept.`name` in ('市场部','销售部'));

2.查询比财务部所有人工资都高的员工信息

-- 2.查询比财务部所有人工资都高的员工
第一种:使用聚合函数
-- 2.1 首先查询财务部的部门id 
select id from dept where dept.`name`='财务部'
-- 2.2然后聚合函数查询财务部的最高工资
select max(emp.salary) from emp where emp.dept_id=(select id from dept where dept.`name`='财务部')
-- 2.3 查询信息
select *from emp where emp.salary >= (select max(emp.salary) from emp where emp.dept_id=(select id from dept where dept.`name`='财务部')); 
第二种:使用列子查询
select *from emp where emp.salary  >= all(select emp.salary from emp where emp.dept_id=(select id from dept where dept.`name`='财务部')); 

3.查询比开发部任何一人工资低的员工信息

-- 3. 查询比研发部其中任意一人工资高的员工信息
第一种: 使用聚合函数
select dept.id from dept where dept.`name`='研发部';
select min(emp.salary) from emp where emp.dept_id = (select dept.id from dept where dept.`name`='研发部');
select *from emp where emp.salary >=(select min(emp.salary) from emp where emp.dept_id = (select dept.id from dept where dept.`name`='研发部'));
第二种:使用列子查询 (some、any)
select *from emp where emp.salary >= some(select emp.salary from emp where emp.dept_id = (select dept.id from dept where dept.`name`='研发部'));

11.子查询-行子查询 (单行但可多列)

返回的结果是一行,比如说查询 和 张无忌的薪资结构相同且领导相同的员工信息。薪资结构和领导都是张无忌一行的数据,一行数据多列字段。

(1).行子查询

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

(2).行子查询示列

1.查询与 张无忌的薪资结构 及 直属领导 相同的员工信息。查询的是张无忌一个

-- 行子查询
-- 1.查询与 张无忌的薪资结构 及 直属领导 相同的员工信息
select salary '薪资结构',managerid '管理者' from emp where emp.`name`='张无忌';
select *from emp where (emp.salary,emp.managerid) =(12500,1);
select *from emp where (emp.salary,emp.managerid) =(select salary '薪资结构',managerid '管理者' from emp where emp.`name`='张无忌');

12.子查询-表子查询 (多行且多列)

比如: 两行分别是 鹿杖客 宋远桥 这两行,两列 分别是 薪资结构和职位。

(1).表子查询

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

(2).表子查询示列

1.1.查询与 鹿杖客 宋远桥 的职位和薪资相同的员工信息

-- 表子查询
-- 1.查询与 鹿杖客 宋远桥 的职位和薪资相同的员工信息
select emp.job,emp.salary from emp where emp.`name` in ('鹿杖客','宋远桥');
-- 这里放in 表示要么一起满足这一行数据,要么一起满足下一行数据
select *from emp where (emp.job,emp.salary) in (select emp.job,emp.salary from emp where emp.`name` in ('鹿杖客','宋远桥'));

2.查询入职日期是 2006-01-01 之后的员工信息,及其部门信息

-- 2. 查询入职日期是 2006-01-01 之后的员工信息,及其部门信息
# 这个方法查询不完整,只查询到了交集,而要求我们查询一张表的全部信息
select *from emp,dept where emp.entrydate > '2006-01-01' and emp.dept_id=dept.id;  
select *from (select * from emp where emp.entrydate> '2006-01-01') as emp_a left join dept on emp_a.dept_id=dept.id;

注意: 我们新派生一张表的时候,我们要给这个新派生的表起别名,否则会报错。

起别名之后:

-- 1.查询员工的姓名,年龄、职位、部门信息 (隐式内连接)
select emp.`name`,emp.age,emp.job,dept.id from emp,dept where emp.dept_id = dept.id;
-- 2.查询年龄小于30岁的员工的姓名,年龄,职位,部门信息(显示内连接)
        #这里一定要使用where,如果使用and的话显示内连接会有效,但是外连接就会无效。
select *from emp join dept on emp.dept_id=dept.id where emp.age>30;
-- 3.查询拥有员工的部门ID、部门名称  (交集)
select DISTINCT dept.id,dept.`name` from dept join emp on dept.id=emp.dept_id;
--  4.查询所有年龄大于40岁的员工,及其归属的部门名称;如果没有分配部门,也需要展示出来 (左外连接)
      #这里千万不要使用and,如果使用and,外连接将会失效
select emp.`name`,dept.`name` from emp left join dept on emp.dept_id = dept.id where emp.age>40;
-- 5.查询所有员工的工资等级 : 员工表和薪资等级表是没有外键关联(直接在笛卡尔积中赛选了)  (隐式内连接)
select  emp.`name`,emp.salary,salgrade.grade from emp,salgrade where emp.salary>=salgrade.losal and emp.salary<=salgrade.hisal;
-- 6.查询 研发部 所有员工的信息及工资等级 (隐式内连接)
    select emp.`name`,emp.salary,dept.`name`,salgrade.grade from emp,salgrade join dept on dept.id=(select id from dept where dept.name='研发部') where emp.salary>=salgrade.losal and emp.salary<=salgrade.hisal;
-- 7.查询研发部 员工的平均薪资 (隐式内连接)
  select avg(emp.salary) from emp  join dept on dept.id=emp.dept_id where dept.id=(select id  from dept where dept.name='研发部');
-- 8. 查询工资比 灭绝 高的员工信息 (联表)
  select * from emp where  emp.salary >(select salary from emp where emp.`name`='灭绝');
-- 9.查询比平均薪资高的员工信息 (联表)
    select *from emp where emp.salary>(select avg(emp.salary) from emp);
-- 10.查询低于本部门平均工资的员工信息  (自连接)
    select * from emp e2 where e2.salary<(select avg(e1.salary) from emp e1 where e1.dept_id =e2.dept_id);
-- 11.查询所有的部门信息,并统计部门的员工人数 (分组)
    select count(*),dept.`name` from emp,dept where dept.id=emp.dept_id GROUP BY emp.dept_id;
-- 12.查询所有学生的选课情况,展示出学生名称、学号、课程名称。
select *from student,course where (student.id,course.id) in (select student_course.studentid,student_course.courseid from student_course)

注意:

  1. on后面的是联查条件,where是非联查条件。非联查条件不能用on;联查条件不能用where。

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
6月前
|
存储 关系型数据库 MySQL
mysql数据基础(1)
mysql数据基础(1)
24 1
|
8月前
|
存储 关系型数据库 MySQL
第02章 MySQL的数据目录【1.MySQL架构篇】【MySQL高级】
第02章 MySQL的数据目录【1.MySQL架构篇】【MySQL高级】
515 0
|
7月前
|
SQL 关系型数据库 MySQL
【MySQL】 MySQL数据库基础
【MySQL】 MySQL数据库基础
|
7月前
|
SQL 存储 关系型数据库
131.【MySQL_基础篇】(一)
131.【MySQL_基础篇】
43 0
|
7月前
|
SQL 关系型数据库 MySQL
131.【MySQL_基础篇】(二)
131.【MySQL_基础篇】
61 0
|
7月前
|
SQL 存储 关系型数据库
131.【MySQL_基础篇】(三)
131.【MySQL_基础篇】
117 0
|
7月前
|
SQL 关系型数据库 MySQL
131.【MySQL_基础篇】(五)
131.【MySQL_基础篇】
48 0
|
7月前
|
SQL 关系型数据库 MySQL
【MySQL 基础介绍】
【MySQL 基础介绍】
50 0
|
8月前
|
存储 关系型数据库 MySQL
1.MySQL架构篇【mysql高级】
1.MySQL架构篇【mysql高级】
73 0
|
9月前
|
SQL 关系型数据库 MySQL
【MySQL】MySQL的优化(二)
【MySQL】MySQL的优化(二)
76 0