SQL进阶-多表查询及相关习题讲解

本文详细讲解了SQL中的多表查询,包括合并结果集、连接查询(内连接、外连接、自然连接)以及子查询的使用。通过实例解析了如何使用子查询解决各种查询条件,如工资高于特定员工、部门所有人的员工信息,以及完全匹配某员工工作和工资的情况。此外,还介绍了如何避免笛卡尔积,并展示了如何将子查询作为条件或表来使用。
摘要由CSDN通过智能技术生成

前言

紧接着之前叙述过的SQL常用语句总结,在这一篇博客中南国也有对多表查询进行了一些叙述,但经过这段时间的笔试面试经历,感觉自己对这块知识的理解 还不够深入。
所以,在这篇SQL进阶中,南国对SQL经常用到的多表知识点在做一个详细的讲解。

提到关系数据库中的多表查询时,你会想到什么呢??
你是不是想说多表查询就是同时查询几张不同的表 通过表与表之间的数据的主外键联系 查询得到想要的数据结果。 当然这个回答已经很不错了,准确的说 多表查询还可以包括同一个数据表中查询大于某行特定数据的查询。

多表查询有如下几种:

  • 合并结果集;
  • 连接查询
    内连接
    外连接:左外连接,右外连接,全外连接(MySQL不支持)
    自然连接
  • 子查询

下面我们对这些方法展开叙述:

1. 合并结果集

这个在前面的博客中,这里我简要叙述一下:
1.作用:合并结果集就是把两个select语句的查询结果合并到一起!
2.合并结果集有两种方式:

  • UNION:去除重复记录,例如:SELECT * FROM t1 UNION SELECT * FROM t2;
  • UNION ALL:不去除重复记录,例如:SELECT * FROM t1 UNION ALL SELECT * FROM t2。
    在这里插入图片描述
    在这里插入图片描述
    3.要求:被合并的两个结果:列数、列类型必须相同。

2. 连接查询

连接查询就是求出多个表的乘积,例如t1连接t2,那么查询出的结果就是t1*t2。
在这里插入图片描述
连接查询会产生笛卡尔积,假设集合A={a,b},集合B={0,1,2},则两个集合的笛卡尔积为{(a,0),(a,1),(a,2),(b,0),(b,1),(b,2)}。可以扩展到多个集合的情况。
那么多表查询产生这样的结果并不是我们想要的,那么怎么去除重复的,不想要的记录呢,当然是通过条件过滤。通常要查询的多个表之间都存在关联关系,那么就通过关联关系去除笛卡尔积。

假如现在有两张表,emp表一共14行记录,dept表一共4行记录,那么连接后查询出的结果是56行记录。
也就你只是想在查询emp表的同时,把每个员工的所在部门信息显示出来,那么就需要使用主外键来去除无用信息了。

SELECT * FROM emp,dept WHERE emp.deptno=dept.deptno;

在这里插入图片描述
上面查询结果会把两张表的所有列都查询出来,也许你不需要那么多列,这时就可以指定要查询的列了。

SELECT emp.ename,emp.sal,emp.comm,dept.dname 
FROM emp,dept 
WHERE emp.deptno=dept.deptno;

在这里插入图片描述

2.1 内连接

上面的连接语句就是内连接,但它不是SQL标准中的查询方式,可以理解为方言!SQL标准的内连接为:

SELECT * 
FROM emp e 
INNER JOIN dept d 
ON e.deptno=d.deptno;

INNER可以省略,因为MySQL默认的连接方式就是内连接

内连接的特点:查询结果必须满足条件。例如我们向emp表中插入一条记录:
在这里插入图片描述
其中deptno为50,而在dept表中只有10、20、30、40部门,那么上面的查询结果中就不会出现“张三”这条记录,因为它不能满足e.deptno=d.deptno这个条件。

2.2 外连接(左连接、右连接)

外连接的特点:查询出的结果存在不满足条件的可能

左连接:

SELECT * FROM emp e 
LEFT OUTER JOIN dept d 
ON e.deptno=d.deptno;

这里OUTER关键字可以省略
左连接是先查询出左表(即以左表为主),然后查询右表,右表中满足条件的显示出来,不满足条件的显示NULL。

例如:其中emp表中“张三”这条记录中,部门编号为50,而dept表中不存在部门编号为50的记录,所以“张三”这条记录,不能满足e.deptno=d.deptno这条件。但在左连接中,因为emp表是左表,所以左表中的记录都会查询出来,即“张三”这条记录也会查出,但相应的右表部分显示NULL。
在这里插入图片描述
右连接:

SELECT * FROM emp e 
RIGHT OUTER JOIN dept d 
ON e.deptno=d.deptno;

右连接就是先把右表中所有记录都查询出来,然后左表满足条件的显示,不满足显示NULL。例如在dept表中的40部门并不存在员工,但在右连接中,如果dept表为右表,那么还是会查出40部门,但相应的员工信息为NULL。
在这里插入图片描述
连接不限与两张表,连接查询也可以是三张、四张,甚至N张表的连接查询。通常连接查询不可能需要整个笛卡尔积,而只是需要其中一部分,那么这时就需要使用条件来去除不需要的记录。这个条件大多数情况下都是使用主外键关系去除。
两张表的连接查询一定有一个主外键关系,三张表的连接查询就一定有两个主外键关系,所以在大家不是很熟悉连接查询时,首先要学会去除无用笛卡尔积,那么就是用主外键关系作为条件来处理。如果两张表的查询,那么至少有一个主外键条件,三张表连接至少有两个主外键条件。

2.3 自然查询

自然连接是把同名列通过等值连接起来的,同名列可以有多个。在等值连接中那目标列中重复的属性列去掉则为自然连接。

内连接和自然连接的区别:内连接提供连接的列,而自然连接自动连接所有同名列。

select Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade
from Student,SC where Student.Sno=SC.Sno;

3. 子查询

子查询就是嵌套查询,即SELECT中包含SELECT,如果一条语句中存在两个,或两个以上SELECT,那么就是子查询语句了。

  • 子查询出现的位置:
    where后,作为条件的一部分;
    from后,作为被查询的一条表;
  • 当子查询出现在where后作为条件时,还可以使用如下关键字:
    any
    all
  • 子查询结果集的形式:
    单行单列(用于条件)
    单行多列(用于条件)
    多行单列(用于条件)
    多行多列(用于表)

关于子查询的理论讲解,我在博客SQL常用语句总结有更新过。子查询比较重要,也应用的比较多。
这里我主要是结合之前的博客 对一些题型做剖析。

1.工资高于甘宁的员工。

分析:
查询条件:工资>甘宁工资,其中甘宁工资需要一条子查询。

第一步:查询甘宁的工资
SELECT sal FROM emp WHERE ename=‘甘宁’

第二步:查询高于甘宁工资的员工
SELECT * FROM emp WHERE sal > (${第一步})

结果:
SELECT * FROM emp WHERE sal > (SELECT sal FROM emp WHERE ename=‘甘宁’)

  • 子查询作为条件
  • 子查询形式为单行单列
2.工资高于30部门所有人的员工信息

分析:
查询条件:工资高于30部门所有人工资,其中30部门所有人工资是子查询。高于所有需要使用all关键字。

第一步:查询30部门所有人工资
SELECT sal FROM emp WHERE deptno=30;

第二步:查询高于30部门所有人工资的员工信息
SELECT * FROM emp WHERE sal > ALL (${第一步})

结果:
SELECT * FROM emp WHERE sal > ALL (SELECT sal FROM emp WHERE deptno=30)

  • 子查询作为条件
  • 子查询形式为多行单列(当子查询结果集形式为多行单列时可以使用ALL或ANY关键字)
3.查询工作和工资与殷天正完全相同的员工信息

分析:
查询条件:工作和工资与殷天正完全相同,这是子查询

第一步:查询出殷天正的工作和工资
SELECT job,sal FROM emp WHERE ename=‘殷天正’

第二步:查询出与殷天正工作和工资相同的人
SELECT * FROM emp WHERE (job,sal) IN (${第一步})

结果:
SELECT * FROM emp WHERE (job,sal) IN (SELECT job,sal FROM emp WHERE ename=‘殷天正’)

  • 子查询作为条件
  • 子查询形式为单行多列
4.查询员工编号为1006的员工名称、员工工资、部门名称、部门地址

分析:
查询列:员工名称、员工工资、部门名称、部门地址
查询表:emp和dept,分析得出,不需要外连接(外连接的特性:某一行(或某些行)记录上会出现一半有值,一半为NULL值)
条件:员工编号为1006

第一步:去除多表,只查一张表,这里去除部门表,只查员工表
SELECT ename, sal FROM emp e WHERE empno=1006

第二步:让第一步与dept做内连接查询,添加主外键条件去除无用笛卡尔积
SELECT e.ename, e.sal, d.dname, d.loc
FROM emp e, dept d
WHERE e.deptno=d.deptno AND empno=1006

第二步中的dept表表示所有行所有列的一张完整的表,这里可以把dept替换成所有行,但只有dname和loc列的表,这需要子查询。

第三步:查询dept表中dname和loc两列,因为deptno会被作为条件,用来去除无用笛卡尔积,所以需要查询它。
SELECT dname,loc,deptno FROM dept;

第四步:替换第二步中的dept
SELECT e.ename, e.sal, d.dname, d.loc
FROM emp e, (SELECT dname,loc,deptno FROM dept) d
WHERE e.deptno=d.deptno AND e.empno=1006

  • 子查询作为表
  • 子查询形式为多行多列

(2019.04.08更新)
这里再分享一个经典的SQL语句初级练习的博客经典数据库SQL语句编写练习题, 供大家学习巩固知识点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值