第六章 复合查询

第六章 复合查询

一、前言

在前面的章节中,我们介绍的是单表查询,但是在本章节中我们要讲解的是多表查询。

二、笛卡尔积

设A,B为集合,用A中元素为第一元素,B中元素为第二元素构成有序对,所有这样的有序对组成的集合叫做A与B的笛卡尔积,记作AxB.

笛卡尔积的符号化为:

A x B = < x , y > ∣ x ∈ A ∧ y ∈ B AxB={<x,y>|x∈A∧y∈B} AxB=<x,y>∣x∈A∧y∈B

例如, A = a , b , B = 0 , 1 , 2 A={a,b},B={0,1,2} A=a,b,B=0,1,2,则

A x B = < a , 0 > , < a , 1 > , < a , 2 > , < b , 0 > , < b , 1 > , < b , 2 > AxB={<a,0>,<a,1>,<a,2>,<b,0>,<b,1>,<b,2>} AxB=<a,0>,<a,1>,<a,2>,<b,0>,<b,1>,<b,2>

B x A = < 0 , a > , < 0 , b > , < 1 , a > , < 1 , b > , < 2 , a > , < 2 , b > BxA={<0,a>,<0,b>,<1,a>,<1,b>,<2,a>,<2,b>} BxA=<0,a>,<0,b>,<1,a>,<1,b>,<2,a>,<2,b>

三、多表查询

1、多表查询的理解

当我们涉及到多表查询的时候,MySQL会将各个表格以笛卡尔积的形式进行拼接,最终拼接为一张表。 所以表面上我们是对多个表进行查询,但实际上我们依旧是在进行单表查询。

2、笛卡尔积与多表拼接

比如我们现在有两个表A和B,那么mysql在拼接的时候,会将A表中每一条语句与B表中的所有语句进行拼接。也就是说,最终会罗列出记录拼接的所有可能。

当mysql进行拼接之后,所谓的多表查询就转化为了单表查询。

但是,由于mysql罗列出了所有的拼接可能,所以在这些拼接的结果中难免会有一些不符合逻辑的记录,此时就需要我们进行适当的筛选。

3、多表查询示例

我们这里使用的是一个新的数据库:scott。

这个数据库中有三个表:dept、emp、salgrade

这三个表的描述如下:

表dept的描述:

表emp的描述:

表salgrade的描述:

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

因为上面的数据来自EMP和DEPT表,因此要联合查询。

我们先看看两个表各自的内容,再看一看两个表拼接后的内容。
emp表的内容如下:

dept的内容如下:

现在将两个表进行拼接,结果如下(由于拼接的结果很长,所以只展示一部分):

上面这个表中有一个缺点,我们发现,表中有两列deptno,但是某些记录在这两列对应的数值并不相等。这些不相等的数据就是我们要筛选掉的。

所以我们可以用如下语句进行筛选:

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

这里形如:表的名称.变量名的语法格式非常像c中的结构体或者是c++中的类。

当我们将表中数据进行正确的筛选后,就可以进行单表查询了。

我们刚刚的需求是:显示雇员名、雇员工资以及所在部门的名字

所以可以使用下面的语句进行筛选:

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

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

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

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

select ename,sal,grade from emp, salgrade where emp.sal between salgrade.losal and salgrade.hisal;

四、自连接

1、什么是自连接

自连接是指同一张表进行连接查询,即自己和自己做笛卡尔积运算。

2、自连接示例

显示员工FORD的上级领导的编号和姓名(mgr是员工领导的编号--empno)

(1)方法一:单表查询:

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

(2)方法二:多表查询:

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

这里用到了给表起别名的方式。

五、子查询

1、什么是子查询

子查询是指嵌入在其他sql语句中的select语句,也叫嵌套查询。其实我们刚刚在介绍自连接的时候, 示例中所用到的第一个方法就是子查询。

2、单行子查询

示例

显示SMITH同一部门的员工

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

3、多行子查询

多行子查询即:返回多行记录的子查询。

(1)in关键字

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

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

(2)all关键字

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

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

(3)any关键字

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

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

4、多列子查询

单行子查询是指子查询只返回单列,单行数据;多行子查询是指返回单列多行数据,都是针对单列而言的,而多列子查询则是指查询返回多个列数据的子查询语句。

(1)示例

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

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

5、在from子句中使用子查询

(1)查询结果作为一张临时表

通过前面的例子,我们发现每次我们执行一个语句后,都会出现一个新的表。那么我们就可以把这个表当作一个临时表作为后续的查询需要。

(2)示例

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

我们先查询一下各个部门的平均工资。形式如下图所示:

现在我们将这个表作为新的表,并且给这个表起名为tmp。接下来就可以按照多表查询的方式去完成我们的题目了。

select ename, emp.deptno, sal, asal from emp,(select deptno, avg(sal) asal  from emp group by deptno)o) tmp where emp.deptno = tmp.deptno and sal > asal;

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

select ename, sal, emp.deptno, msal from emp,(select deptno, max(sal) msal from emp group by deptno)) tmp where emp.deptno = tmp.deptno and emp.sal = msal;

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

6、合并查询

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

(1)union

作用

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

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

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

(2)union all

作用

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

示例:将工资大于25000或职位是MANAGER的人找出来

select ename, sal, job from emp where sal > 2500 union all  select ename, sal, job from emp where job = 'MANAGER';
相关推荐
苹果醋31 小时前
React源码02 - 基础知识 React API 一览
java·运维·spring boot·mysql·nginx
了一li2 小时前
Qt中的QProcess与Boost.Interprocess:实现多进程编程
服务器·数据库·qt
码农君莫笑2 小时前
信管通低代码信息管理系统应用平台
linux·数据库·windows·低代码·c#·.net·visual studio
别致的影分身2 小时前
使用C语言连接MySQL
数据库·mysql
过过过呀Glik2 小时前
在 Ubuntu 上安装 MySQL 的详细指南
mysql·ubuntu
京东零售技术4 小时前
“慢”增长时代的企业数据体系建设:超越数据中台
数据库
sdaxue.com4 小时前
帝国CMS:如何去掉帝国CMS登录界面的认证码登录
数据库·github·网站·帝国cms·认证码
o(╥﹏╥)5 小时前
linux(ubuntu )卡死怎么强制重启
linux·数据库·ubuntu·系统安全
阿里嘎多学长5 小时前
docker怎么部署高斯数据库
运维·数据库·docker·容器
Yuan_o_5 小时前
Linux 基本使用和程序部署
java·linux·运维·服务器·数据库·后端