MySQL复合查询

MySQL复合查询

基本查询回顾

eg:测试表-----来自oracle 9i的经典测试表

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

分析:

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

按照部门号升序而雇员的工资降序排序

分析:

SQL语句:
select ename,deptno,sal from emp order by deptno ASC,sal DESC;

使用年薪进行降序排序

分析:

年薪=月工资*12+奖金;

通过查表可知,我们知道奖金是有可能为null的,二任何数与null运算的结果都是null,这显然不是我们想要的,我们希望,当某个人的奖金为null时,加的是0,因此SQL语句:
select ename,sal*12+ifnull(comm,0) as 年薪 from emp order by 年薪 DESC;

显示工资最高的员工的名字和工作岗位

分析:

1、我们可以先筛选出最高工资:

SQL语句:
select max(sal) from emp;

  1. 基于上面筛选出来的最高工资继续使用select子句查询员工名字、工作岗位;

SQL语句:
select ename,job from emp where sal =(select max(sal) from emp);

显示平均工资低于2000的部门号和它的平均工资

分析:

SQL语句:
select deptno,avg(sal) as 平均工资 from emp group by deptno having avg(sal)<2000;

显示每种岗位的雇员总数,平均工资

分析:

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

多表查询

实际开发中往往数据来自不同的表,所以需要多表查询。本节我们用一个简单的公司管理系统,有三张表EMP,DEPT,SALGRADE来演示如何进行多表查询

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

分析:

首先雇员名、雇员工资在emp表中,部门号在dept表中

为此我们需要从emp中获取数据,也要从dept表中获取数据,为此在from的时候,我们可以这样写:
select * from emp,dept;

我们会得到一张很大的表,这张表是怎么来的?

当我们读取多张表的时候,这多张表会做笛卡尔积,以本题为例,就是将emp中的每一条数据与dept中的每一条数据组合形成一条条数据,后面一次类推...

对于上表的结果,我们可以先筛选有意义的结果,就比如一个20号部门的员工,我们就没必要看10号部门的信息了,因此我们先筛选出emp.deptno=dept.deptno的数据,也就是有意义的数据:
select * from emp,dept where emp.deptno=dept.deptno;

然后我们就可以是筛选出:雇员名、雇员工资以及所在部门的名字的数据;

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

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

分析:

首先通过题目要求我们显示部门名、员工名、工资,而部门名和员工名、工资是两个不同表中的数据,因此我们需要进行多表查询,将emp表和dept表做笛卡尔积,然后筛选出有意义的数据以及部门号等于10的数据;

SQL语句:
select ename,sal,dname,emp.deptno from emp,dept where emp.deptno=dept.deptno and emp.deptno=10;

显示各个员工的姓名,工资,及工资级别

分析:

首先员工姓名这些信息在emp表中,而工资级别在salgrade表中,因此我们本次查询需要进行多表查询,因此首先emp表与salgrade表进行笛卡尔积,如果想要筛选出有意义的数据我们就得首先将有意义的数据筛选出来,就比如:张三工资800¥,它的工资等级就不可能是2、3、4、5级别,只能是1等级,为此有意义的数据的筛选条件是:sal betweent losal and hisal;

SQL语句:
select ename,sal,grade from emp,salgrade where sal between losal and hisal;

自连接

上面我们说的多表查询是多个不同的表之间,那么多表查询可不可以在多个相同的表之间进行呢?

当然可以,我们将这种多表查询叫做自连接;

在进行自连接的时候,我们需要将表取个别名,不然MySQL语法会报错:

也就是以不同名字告诉MySQL,让MySQL通过语法检测:

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

分析:

  1. 子查询方式:
    如果采用子查询方式的话,我们可以先筛选出FORD的上级领导:
    SQL语句:select mgr from emp where ename='FORD;'

    然后的话我们再根据FORD的上级领导工号筛选出FORD的上级领导:
    SQL语句: select empno,ename from emp where empno=(select mgr from emp where ename='FORD');

    当然既然我们这里实现了自连接,我们也就可以采用自链接的方式来做;
  2. 自链接作法:
    分析:上级领导的信息和FORD的信息都来自于emp表,为此我们对其进行自链接,然后筛选出正确信息:
    SQL语句:
    select leader.empno,leader.ename from emp as worker,emp as leader where worker.ename='FORD' and worker.mgr=leader.empno;

子查询

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

单列单行子查询

返回一列一行记录的子查询

显示SMITH同一部门的员工

分析:

  1. 首先筛选出SMITH的部门:
    SQL语句: select deptno from emp where ename='SMITH';
  2. 然后基于上面查询出来的结果,筛选出部门号为20的数据:
    SQL语句: select * from emp where deptno=(select deptno from emp where ename='SMITH');

    向上面子查询结果出来的是一张单行单列的表我们就称为**单列单行子查询;**这时可以直接将子查询表中的结果作为where的筛选条件;

单列多行子查询

返回单列多行记录的子查询

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

分析:

  1. 首先我们可以先查询出10号部门的工作岗位:
    SQL语句:select distinct job from emp where deptno=10;

    注意: 有可能查询出同部门同工作岗位的员工数据,因此这样的话查出来的job数据就会有重复的,为此我们需要对于查出来的job列进行去重;
    2 . 在基于上面的结果筛选出工作岗位是其中之一的员工数据并且不办包含10号部门自己的人:
    那么如何才能做到job是上述结果之一呢?in 关键字出场;具体如下操作:
    SQL语句:
    select ename,job,sal,deptno from emp where job in (select distinct job from emp where deptno=10) and deptno <> 10;

显示工资比30号部门的所有员工的工资都高的员工的姓名、工资和部门号

分析:

  1. 先查询出30号部门的所有员工的工资:
    然后有可能工资有相同的因此我们可以对于查询出来的工资进行去重
    SQL语句:
    select distinct sal from emp where deptno=30;
  2. 然后基于上述查询结果筛选出工资大于30号部门所有员工工资的员工信息:
    SQL语句:
    select ename,sal,deptno from emp where sal > all (select distinct sal from emp where deptno=30) and deptno<>30;

    这里我们主要想讲解all关键字,all表示所有;
    当然这里除了上面的作法,我们还有第二种作法,第二种作法就是,我们不是要求工资高于30号部门的所有员工的工资的员工数据吗?换个思路要求高于30号部门所有员工的工资不就是要求高于30号部门的最高工资的员工信息吗?

按照这个思路,

  1. 我们可以先求出30号部门的最高工资:
    SQL语句:select max(sal) from emp group by deptno having deptno=30;
  2. 在基于上面的结果筛选出工资高于2850的员工信息:
    SQL语句:
    select ename,sal,deptno from emp where sal >(select max(sal) from emp group by deptno having deptno=30) and deptno <> 30;

显示工资比部门30的任意员工的工资高的员工的姓名、工资和部门号(包含自己部门的员工)

分析:

  1. 先查询出30号部门的所有员工的工资:
    然后有可能工资有相同的因此我们可以对于查询出来的工资进行去重
    SQL语句:
    select distinct sal from emp where deptno=30;

  2. 再基于上述结果查询比起任意工资都高的数据的信息:
    这里我们使用any 关键字:
    SQL语句:
    select ename,sal,deptno from emp where sal >any(select distinct sal from emp where deptno=30);

    实际上这道题也有另一种查询方式,题目要求只要我们查出来员工数据比30号部门任意一个员工的工资高就行了,那么换而言之不就是要求我们查询工资高于30号部门最低工资的员工数据吗?

  3. 先筛选出30号部门的最低工资:
    SQL语句: select min(sal) from emp group by deptno having deptno =30;

  4. 基于上面筛选结果继续筛选出sal>30号部门最低工资的员工数据:
    SQL语句:
    select ename,sal,deptno from emp where sal>( select min(sal) from emp group by deptno having deptno =30);

多列单行子查询

单行单列子查询是指子查询只返回单列,单行数据;多行单列子查询是指返回单列多行,一列数据;而多列子查询则是指查询返回多个列数据的子查询语句;

查询和SMITH的部门和岗位完全相同的所有雇员,不含SMITH本人

分析:

  1. 首先查询出SMITH的部门号和岗位:
    select deptno ,job from emp where ename='SMITH';

    像这样查询出来的子表具有多列单行记录的查询叫做多列单行子查询(不是指本次子查询,而是整体的查询);

  2. 基于上述结果筛选出合法数据:

    SQL语句:
    select * from emp where (deptno,job) =(select deptno ,job from emp where ename='SMITH') and ename!='SMITH';

在from子句中使用子查询

子查询语句出现在from子句中。这里要用到数据查询的技巧,把一个子查询当做一个临时表使用。

在MySQL中,我们可以以一个'万物皆表'的思想来看待;

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

分析:

  1. 先查询出每个部门的平均工资:
    SQLselect deptno, avg(sal) from emp group by deptno ;
  2. 然后的话我们可以把这张查询出来的数据也看做是'一张表',为此我们可以将这张表与emp表做符合查询,并且我们可以根据条件筛选出最终结果:
    SQL语句:
    select ename,sal,emp.deptno,t2.deptno,平均工资 from emp,( select deptno,avg(sal) as 平均工资 from emp group by deptno) as t2 where emp.sal >平均工资 and emp.deptno<> t2.deptno;;

查找每个部门工资最高的人的姓名、工资、部门、最高工资

分析:

  1. 先筛选出每个部门的最高工资:
    SQL语句:
    select deptno,max(sal) as 最高工资 from emp group by deptno;
  2. 将上面查询出来的数据作为临时表与emp表做笛卡尔积,然后再进行查询:
    SQL语句:
    select ename,sal,emp.deptno,t2.deptno,最高工资 from emp,(select deptno,max(sal) as 最高工资 from emp group by deptno) as t2 where emp.sal<=>最高工资 and emp.deptno <=> t2.deptno;

显示每个部门的信息(部门名,编号,地址)和人员数量

分析:

  1. 先是筛选出每个部门的人数:
  2. 然后我们可以基于上面的临时表与dept表做笛卡尔积,筛选出符合条件的数据:
    SQL语句:
    select dept.deptno,dname,loc,总人数 from dept,(select deptno,count(*) as 总人数 from emp group by deptno) as t2 where dept.deptno<=> t2.deptno

合并查询

在实际应用中,为了合并多个select的执行结果,可以使用集合操作符 union,union all

在使用合并的时候需要注意:两个表的列字段必须完全一样,无论那一张表多一个少一个都不行;

union

操作符用于取得两个结果集的并集。当使用该操作符时,会自动去掉结果集中的重复行

工资大于2500或职位是MANAGER的人找出来

分析:

SQL语句:
select * from emp where sal>2500 union select * from emp where job='MANAGER';

union all

该操作符用于取得两个结果集的并集。当使用该操作符时,不会去掉结果集中的重复行

将工资大于2500或职位是MANAGER的人找出来

SQL语句:
select * from emp where sal>2500 union all select * from emp where job='MANAGER';

相关推荐
百***92023 小时前
【MySQL】MySQL库的操作
android·数据库·mysql
q***76663 小时前
Spring Boot 从 2.7.x 升级到 3.3注意事项
数据库·hive·spring boot
信仰_2739932434 小时前
Redis红锁
数据库·redis·缓存
人间打气筒(Ada)4 小时前
Centos7 搭建hadoop2.7.2、hbase伪分布式集群
数据库·分布式·hbase
心灵宝贝4 小时前
如何在 Mac 上安装 MySQL 8.0.20.dmg(从下载到使用全流程)
数据库·mysql·macos
想睡hhh4 小时前
mysql索引——理解索引机制及操作
mysql
剑动山河4 小时前
ubuntu 升级mysql由mysql5.7.42 升级到8.4.0
mysql·ubuntu·adb
奋斗的牛马5 小时前
OFDM理解
网络·数据库·单片机·嵌入式硬件·fpga开发·信息与通信
忧郁的橙子.5 小时前
一、Rabbit MQ 初级
服务器·网络·数据库
杰杰7986 小时前
SQL 实战:用户访问 → 下单 → 支付全流程转化率分析
数据库·sql