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

【MySQL】复合查询与内外连接

目录

一、复合查询

1、基本查询回顾:

2、多表查询:

3、自连接:

4、子查询:

单列子查询

多行子查询:

多列子查询:

在from语句中使用子查询:

5、合并查询:

union:

union all:

二、内外连接:

1、内连接:

2、外连接:

左外连接:

右外连接:


这里依然是使用经典数据表:员工表(emp)、部门表(dept)和工资等级表(salgrade)

如下是员工表,分别是empno员工号/ename员工姓名/job工作/mgr上级编号/hiredate受雇日期/sal薪金/comm佣金/deptno所属部门编号

如下是部门表,分别是deptno部门编号,dname部门名称,loc部门所在地

如下是薪资等级:

一、复合查询

1、基本查询回顾:

查询工资高于500或岗位为MANAGER的员工,同时还要满足他们的名字的首字母大写的J

select * from emp where (sal>500 or job='MANAGER') and ename like 'J%';

除了用模糊匹配,还有字符串切割也可以

select * from emp where (sal>500 or job='MANAGER') and substring(ename,1,1)='J';

查询员工信息,按部门号升序而员工工资降序显示

select ename,sal,deptno from emp order by deptno asc ,sal desc;

查询员工信息,按年薪降序显示

select * from emp order by 12*sal+ifnull(comm,0) desc;

员工的年薪为月工资*12+年终奖,但是这里不能够直接12*sal+comm,因为comm可能为NULL,此时如果用NULL运算就会使结果为空

所以需要使用函数ifnull,如果comm为NULL就将其设置为0

查询工资最高的员工的姓名和岗位

首先查看工资最高是谁,这里使用聚合函数:

select max(sal) from emp;

当查询到最高工资的人后,可以将这个结果放到where语句中作为判断条件,也就是说where语句中可以进行查询:

select ename,job from emp where sal=(select max(sal) from emp);

查询工资高于平均工资的员工信息

首先依然是查询员工的平均工资:

select avg(sal) from emp;

接着将这个语句嵌套在where中作为判断:

select * from emp where sal>(select avg(sal) from emp);

查询每个部门的平均工资和最高工资

既然是每个部门,就需要进行分组

select deptno,avg(sal) 平均工资,max(sal) 最高工资 from emp group by deptno;

查询平均工资低于2000的部门号和它的平均工资

select deptno,avg(sal) 平均工资 from emp group by deptno having avg(sal)<2000;

这里因为是进行分组查询,不能使用where,需要使用having来进行条件判断

查询每种岗位的雇员总数和平均工资

人数用count()函数进行统计

select job,count(*) 人数,avg(sal) 平均工资 from emp group by job;

2、多表查询:

在上述基本查询中,都是在单表中进行查询的,但是在实际开发中,更多的是多个表综合起来进行查询的,这就叫做多表查询

笛卡尔积:
在进行多表查询的时候,将多个表名放在from后面并用逗号隔开,这是,MySQL就会对这些表取笛卡尔积,组成一张新表

进行笛卡尔积转化后:

笛卡尔积的本质是拿着第一张表的信息 依次 和第二张表的所有信息进行组合,这样形成地一张表

多表查询的本质:对给的多张表取笛卡尔积,然后对笛卡尔积后的表进行查询

在进行笛卡尔积的多张表中可能会存在相同的列名,这时在选中列名时需要通过(表名.列明)的方式进行指明

显示雇员名,雇员工资以及所在部门的名字

这里雇员名和雇员工资是在同一张表中的,但是所在部门名字是在另一张表中的,所以需要对这两张表进行笛卡尔积,然后在进行查询即可

通过上述图片可以看到,比如Smith他的部门号有两个,这里是取相等的,其他的就是没有意义的数据,所以需要进行初步筛选:

select * from emp,dept where emp.deptno=dept.deptno;

最后在将*修改为所需即可

select ename,sal,dname from emp,dept where emp.deptno=dept.deptno;

显示部门号为10的部门名、员工名和员工工资

这里部门名和其他是在不同的表中的

select dname,ename,sal from emp,dept where emp.deptno=dept.deptno and emp.deptno=10;

显示各个员工的姓名、工资和工资级别

这里工资级别和其他是不同的表中:

需要where增加的条件是工资处于最低和最高之间工资筛选出来,才有意义

3、自连接:

自连接是在同一张表进行连接查询,也就是说对同一张表进行取笛卡尔积,

显示员工FORD的上级领导的编号和姓名

子查询解决:

首先找到FORD的上级领导的编号,

select mgr from emp where ename='FORD';

接着通过嵌套找到对应编号的姓名

select empno,ename from emp where empno=(select mgr from emp where ename='FORD');

自连接解决:

员工表中的mgr字段能够将表中员工的信息和员工领导的信息关联起来

mysql> select leader.empno,leader.ename from emp leader,emp worker-> where worker.ename='FORD' and leader.empno=worker.mgr;

这里是对同一张表进行取笛卡尔积的,所以需要对其取别名来区别开来

4、子查询:

子查询是指嵌入在其他sql语句中的select语句,也叫嵌套查询

子查询可分为单行子查询,多行子查询,多列子查询,以及在from子句中使用的子查询

单列子查询

显示SMITH同一部门的员工

首先显示SMITH的部门

select deptno from emp where ename='SMITH';

接着将这个语句嵌套在where判断中,作为嵌套的子语句,再来查询对应的员工

select * from emp where deptno=(select deptno from emp where ename='SMITH') and ename<>'SMITH';

多行子查询:

回多行单列数据的子查询

in关键字:查询和 10 号部门的工作岗位相同的雇员的名字,岗位,工资,部门号,但是不包含 10 自己的

首先查询10号部门的工作岗位,这里要进行去重,因为可能不同的人在同一个部门有着相同的工作岗位

这里查出来和之前不同的是这里查询的是单列多行的,只要岗位和这里面一个相同就可以,用in关键字

select ename,job,sal,deptno from emp where job in(select distinct job from emp where deptno=10) and deptno<>10;

all关键字:显示工资比30号部门的所有员工的工资高的员工的姓名、工资和部门号

先查询30号部门的所有员工的工资,因为工资可能相等,所以这里最好去重

接着在进行嵌套,为了保证所查出来的工资比30号部门的所有员工的工资高,这里使用all关键字

any关键字:显示工资比30号部门的任意员工的工资高的员工的姓名、工资和部门号,包含30号部门的员工

首先查询30号部门的员工的工资:

select distinct sal from emp where deptno=30;

接着通过关键字any进行员工的查看:

select ename,sal,deptno from emp where sal>any(select distinct sal from emp where deptno=30);

多列子查询:

这是返回多列多行的查询

显示和SMITH的部门和岗位完全相同的员工,不包含SMITH本人

首先显示SMITH的部门和岗位:

select deptno,job from emp where ename='SMITH';

接着通过复合查询,将上述的查询放在where后面作为子查询

这里是采用的多列查询,所以在where后面匹配的时候通过括号进行多列匹配,并且在后面记得保证名字不能为SMITH

也就是说,多列子查询在where匹配的时候要用括号将多列数据进行比较,并且如果数据是多行的,也可以使用in,all,any关键字

在from语句中使用子查询:

我们知道from后面跟着的是表,在MySQL下一切皆表,所以可以将一个查询结果当做临时表,放在from语句的后面

显示每个高于自己部门平均工资的员工的姓名、部门、工资和部门的平均工资

首先查询每一个部门其自己的平均工资:

select deptno,avg(sal) from emp group by deptno;

接着将如上表和员工表取笛卡尔积,然后再通过部门号相等删除部分无效数据,最后where筛选出高于自己部门平均工资的员工的数据

mysql> select ename,emp.deptno,sal,平均工资-> from emp,(select deptno,avg(sal) 平均工资 from emp group by deptno) newtable-> where emp.deptno=newtable.deptno and sal>平均工资;

注意:在from子句的查询中,必须给子查询所生成的临时表取一个别名,否则查询结果会出错找不到对应的字段,并且如果两张表中有相同的字段,要指定其是在哪张表的,否则也会报错

显示每个部门工资最高的员工的姓名、工资、部门和部门的最高工资

首先查询每个部门的最高工资的员工:

select deptno,max(sal) from emp group by deptno;

接着将上述表和员工表进行笛卡尔积,在进行筛选即可

mysql> select ename,sal,emp.deptno,最高工资-> from emp,(select deptno,max(sal) 最高工资 from emp group by deptno) newtable-> where emp.deptno=newtable.deptno and sal=最高工资;

5、合并查询:

为了合并多个select查询结果,可以通过操作符union和union all进行合并查询

union:

用于取得两个查询结果的并集,union会自动去掉结果集中的重复行

显示工资大于2500或职位是MANAGER的员工

首先查询工资大于2500员工:

select * from emp where sal>2500;

接着查询职位是MANAGER的员工:

select * from emp where job='MANAGER';

为了完成上述,可以使用or关键字:

select * from emp where sal>2500 or job='MANAGER';

或者使用union关键字:

select * from emp where sal>2500 union select * from emp where job='MANAGER';

union all:

该操作符用于取得两个结果集的并集,与union不同的是,这个不会对结果进行去重:

select * from emp where sal>2500 union all select * from emp where job='MANAGER';

注意:待合并的两个查询结果的列的数量必须一致,否则无法合并

二、内外连接:

表的连接分为内连接和外连接

1、内连接:

内连接实际上就是利用where子句对两种表形成的笛卡儿积进行筛选,我们前面学习的查询都是内连接,也是在开发过程中使用的最多的连接查询

语法:

select 字段 from 表1 inner join 表2 on 连接条件 and 其他条件;
显示 SMITH 的名字和部门名称

其实完成上述查询可以不使用内连接,用以前学习的已经够了,只是内连接能够让我们的查询逻辑更清楚

在上述的查询中,我们可以使用以前学习的笛卡尔积

select emp.ename,dept.dname from emp,dept where emp.deptno=dept.deptno and emp.ename='SMITH';

除了笛卡尔积这种写的方式,我们还可以用内连接的写法:

select ename,dname from emp inner join dept on emp.deptno=dept.deptno and ename='SMITH';

2、外连接:

左外连接:

如果想让左侧的表完全显示,右侧的表如果和左侧的表没有匹配的就去掉,就使用左外连接,其语法和内连接一模一样只是将inner这个关键字修改为left

select 字段 from 表1 left join 表2 on 连接条件 and 其他条件;

示例:

首先创建一个测试表:

查询所有学生的成绩,如果这个学生没有成绩,也要将学生的个人信息显示出来
select * from stu left join exam on stu.id=exam.id;

尽管在exam这个右侧表中,没有王五赵六的成绩信息,但是他们仍然被显示出来了,左连接更偏向于左边的表

右外连接:

右外连接和左外连接就是相反的了,比如上述要求我们改为:

查询所有成绩,如果这个成绩没有对应的学生,也要将这个成绩显示出来

select * from stu right join exam on stu.id=exam.id;

但事实上,左外连接和右外连接是可以相互转换的

相关文章:

  • 日语学习-日语知识点小记-构建基础-JLPT-N4阶段(13): ておきます ています & てあります
  • OpenGL-ES 学习(15) ----纹理
  • 【Unity】 组件库分类详解
  • 【计算机视觉】语义分割:MMSegmentation:OpenMMLab开源语义分割框架实战指南
  • OpenGL-ES 学习(12) ---- VBO EBO VAO
  • 动态规划引入
  • 【Dify系列教程重置精品版】第五章:Dify配置Ollama
  • C# System.Text.Json终极指南(十):从基础到高性能序列化实战
  • MCP 多工具协作链路设计:打造真正的智能工作流
  • 补题:K - Magic Tree (Gym - 105231K)
  • SpringBoot研究生双选系统开发实现
  • Rust中避免过度使用锁导致性能问题的策略
  • C# | 基于C#实现的BDS NMEA-0183数据解析上位机
  • 详解TypeScript中的类型断言及其绕过类型检查机制
  • Python 从入门到精通3 控制结构
  • 深度学习基础--目标检测入门简介
  • 软件工程国考
  • 使用Python和Pandas实现的Azure Synapse Dedicated SQL pool权限检查与SQL生成用于IT审计
  • PyTorch 与 TensorFlow:深度学习框架的深度剖析与实战对比
  • 等保系列(一):网络安全等级保护介绍
  • 旭辉控股集团:去年收入477.89亿元,长远计划逐步向轻资产业务模式转型
  • 海警巡航时海豚围舰艇嬉戏,专家:证明海域生态环境持续向好
  • 停电催生商机,中国品牌 “照亮” 西班牙
  • 市场监管总局出手整治涉企乱收费,聚焦政府部门及下属单位等领域
  • 中央网信办:重点整治违规AI产品、利用AI制作发布谣言等突出问题
  • 江西德安回应“义门陈遗址建筑被没收”:将交由规范的义门陈相关社会组织管理