数据库原理与应用系列_02子查询

简介: 出现在其他语句中的select语句,称为子查询或内查询外部的查询语句,称为主查询或外查询

一、子查询概述



定义:

  • 出现在其他语句中的select语句,称为子查询或内查询
  • 外部的查询语句,称为主查询或外查询

为什么要学习子查询?

例:查询工资比张三高的员工信息

 -- 查询工资比张三高的员工信息
 -- 1.查询张三的工资
 select sal from emp where ename='张三';
 -- 2. 比3000元高的员工信息
 select * from emp where sal >3000;

张三的工资是3000元,这3000元是作为条件,在第二步当作为条件使用。

这里需要两个步骤,而使用子查询之后,使用一步就可以解决该问题。

因此子查询要解决的问题是:问题不能一步求解的问题。


二、子查询的使用



子查询的语法:select语句的嵌套。

 SELECT select_list 
 FROM table 
 WHERE expr operator (    
    SELECT select_list 
    FROM table
 )

使用子查询解决:查询工资比张三高的员工信息

 select * 
 from emp 
 where sal > (
      select sal
      from emp 
      where ename='张三'
);

子查询注意的10个问题:

【1】子查询语法中的小括号

60c5f81bdcd4423094b8c72fdd309038.png

select e.*
from sal > (select min(sal) from emp where deptno=30)

【2】子查询的书写风格

【3】可以使用子查询的位置:where,select,having,from

【4】不可以使用子查询的位置:group by

【5】强调:from 后面的子查询语句

【6】子查询和主查询可以不是同一张表


只要子查询的结果在主查询当中可以使用就行了。


例子:查询部门名称是行政部的员工信息

--方法一:使用子查询
-- 这里子查询是使用表dept,而外层则是使用emp表
select * 
from emp 
where deptno=(select deptno
        from dept 
        where dname='行政部')
--方法二:使用多表查询
-- 从理论上面来讲,使用多表查询好于子查询
select e.*
from emp e,dept d
where e.deptno=d.deptno and d.dname='行政部'

【7】一般不在子查询中,使用排序(因为没有意义);

但是在Top-N分析问题中,必须对子查询排序


Top-N分析问题:指的是按照某个规律排序以后,取出前几条记录。


【8】一般先执行子查询,再执行主查询,但相关子查询例外

【9】单行子查询只能使用单行操作符;多行子查询只能使用多行操作符

【10】注意子查询中是null值问题:子查询分为单行子查询和多行子查询


1、单行子查询


  1. 单行子查询:子查询只返回一条记录

单行操作符:= , > , >= ,< <= ,<>

单行子查询事例:

select * 
from emp 
where job=(select job from emp where empno=7655) and 
    sal>(select sal from emp where empno=6088);

822396cccdb84ae5ace6ee7c855ae984.png

-- 查询工资最低的员工的信息
select * 
from emp 
where sal=(select min(sal) from emp) -- 在子查询当中也可以使用分组函数
-- 查询最低工资大于20号部门最低工资的部门号和部门的最低工资:
--先得到每个部门的最低工资,在查出20号部门的最低工资,然后筛选
select deptno ,min(sal)
from emp 
group by deptno 
having min(sal) > (select min(sal)
            from emp 
            where deptno=20)

90010e8c8bca4fd0a86d7ad02ffceca8.pngbe40a749803047de97e6c7e017cafb95.png


2、多行子查询


d6b534b38f6d4774bd3bb3ce042335a1.png89f23665a16443bc9c9545d2fe245af5.png9a442d5ccf4b4f288fc79b14cd1e1103.png

  1. 多行子查询:子查询返回多条记录

多行操作符:


【1】in

【1】IN:等于列表中的任何一个

例子: 查询部门名称是销售部或者财务部的员工信息

方法一:子查询+in

-- 方法一:子查询+in 
select * 
from emp 
where deptno in (select deptno 
        from dept
        where dname='销售部' or dname='财务部')

edde650e602140bc9c11818ed760a1d1.png

方法二:使用多表查询

select e.* -- 查询员工的所有信息
from emp e,dept d
where e.deptno=d.deptno and (d.dname='销售部' or d.dname='财务部')

0195331cba854922b56f585d4953b14e.png


【2】any


【2】ANY:和子查询返回的任意一个值比较

ANY在使用中有如下三种使用形式:

  • =ANY:表示与子查询中的每个元素进行比较,功能与IN类似(然而<>ANY不等价于NOT IN)

b7294cc78bc64c6a9c77d5c5303e7b1a.png

  • >ANY:比子查询中返回结果的最小的要大(还包含了>=ANY)
  • <ANY:比子查询中返回结果的最大的要小(还包含了<=ANY)

例子:查询工资比30号部门任意一个员工高的员工信息

方法一:

select e.*
from sal > any (select sal from emp where deptno=30)

方法二:

-- 分析:大于任意一个,只要大于最小的那个就行了
select e.*
from sal > (select min(sal) from emp where deptno=30)


【3】all

ALL操作符有以下三种用法:

<>ALL:等价于NOT IN(但是=ALL并不等价于IN)

>ALL:比子查询中最大的值还要大(还包含了>=ALL)

<ALL:比子查询中最小的值还要小(还包含了<=ALL)

【3】ALL:和子查询返回的所有值比较


例子:查询工资比30号部门所有员工高的员工信息


方法一:使用子查询的any

select e.*
from sal>  any ( select  sal from emp where deptno=30)

方法二:大于子查询的最大值即可

select e.*
from sal>  ( select  max(sal) from emp where deptno=30)
  1. 在where后面使用子查询
 select * 
 from emp 
 where sal>(
      select sal
      from emp 
      where ename='张三'
);
  1. 在select后面使用子查询

在select后面使用子查询必须是单行子查询

-- 错误写法,因为此时子查询是多行记录
select empno,ename,sal,(select job from emp )
--正确写法:
select empno,ename,sal,(select job from emp where empno=7893) from emp;
  1. 在having后面使用子查询
select deptno,avg(sal)
from emp
group by deptno 
having avg(sal) > (select max(sal)
          from emp
          where deptno=30);
  1. 在from后面使用子查询
select *
from ( select empno,ename,sal from emp )
--例一:查询员工信息:员工号,姓名,月薪
select * 
from (select empno,ename,sal from emp)
--例二:查询员工信息:员工号,姓名,月薪,年薪
select * 
from (select empno,ename,sal,sal*12 as annsal from emp)

【4】exists [考]

【1】当EXISTS语句中的查询结果为非空时返回值为True

【2】当EXISTS语句中的查询结果为空时返回值为False

【3】exists是存在一个即可返回真,not exists是全都不存在才返回真


EXISTS也可进行相关的子查询,带有EXISTS的子查询不返回任何实际的数据,它只得到逻辑值‘真’或者‘假’。当子查询的结果集合为非空时,外层WHERE子句返回针织,否则返回假值。


NOT EXISTS 则相反,如果子查询的结果为非空,而外面使用了NOT EXISTS,则得到的结果为假。

5ab553080c194bcaa5523ba8c740077e.png74100c773dea42549571602a2fcf92bd.png505c04bad4864fa0bcac34f920a0bbfd.png

-- 关于exists和 not exists
 SELECT EMPID,EMPNAME FROM EMPLOYEES
 WHERE NOT EXISTS
 (
  SELECT EMPRESPECT FROM EMPLOYEES
  WHERE NOT EXISTS
  (
    SELECT * FROM ORDERS WHERE 1=2
  )
 )

如果想要得到一张表的框架,而不得到表的结构,则也可以使用上面的方法:

SELECT EMPID,EMPNAME INTO TEMP123 FROM EMPLOYEES
WHERE 1=2

3516ffd7f88147e3993f93253d6efb06.png3516ffd7f88147e3993f93253d6efb06.png

使用嵌套EXISTS:

c642f560cd374b7a8ab3afb50be7658c.png


最后一个示例是双嵌套 NOT EXISTS查询。也就是说,它在NOT EXISTS子句中还有一个NOT EXISTS子句。在形式上,它回答了“一个城市是否存在一个不在商店里的商店”﹖但更容易说,嵌套的不存在回答了问题“X对所有Y都是真的吗?”。

8f01d3edf7ee42529e704918fb83aa4b.png

SELECT  A FROM RRR R1
WHERE NOT EXISTS
(
  SELECT B,C FROM TTT
  WHERE  NOT EXISTS
  (
    SELECT * FROM RRR R2
    WHERE R2.B=TTT.B AND R2.C=TTT.C AND R2.A=R1.A
  )
)

64505876fdb74fd8b43fad4794a1a607.png

双重否定等于肯定:

SELECT  A FROM RRR R1
WHERE NOT EXISTS
(
  SELECT B,C FROM TTT
  WHERE  NOT EXISTS
  (
    SELECT * FROM RRR R2
    WHERE (R2.B+R2.C)=(TTT.B+TTT.C) AND R2.A=R1.A
  )
)
 --查询购买了所有产品的客户姓名
 -- 出来的结果是所有的公司,用了三重否定
 -- 如果在三层嵌套中任意两层使用not 剩下一层使用exists,则得到的就是正确的结果:即没有一家公司购买的是所有产品
 SELECT CUSTNAME 
 FROM CUSTOMERS C1
 WHERE NOT EXISTS
 (
  SELECT * FROM ORDERS O1
  WHERE NOT EXISTS
  (
    SELECT * FROM ORDERDETAIL O2
    WHERE  EXISTS
    (
      SELECT * FROM PRODUCTS P
      WHERE P.PNAME=O2.PNAME AND O1.ORDERID=O2.ORDERID AND O1.CUSTID=C1.CUSTID
    )
  )
 )


3、子查询中的空值问题



【1】单行子查询当中的空值问题

必须使用in或者

165ccce8628d42a09f2669dcb8da28e7.png

由于条件为假,因此子查询不返回任何值。

【2】多行子查询当中的空值问题

例子:查询不是老板的员工

86ab853b6d094550a996ef8f9f8db803.png

在emp表当中,有一列MGR,代表该员工的老板的编号

c8d9d25b96974df7a7d8bb6b313abe06.png453afb9890824384943de44fb6c1ac89.png

为什么not in得不到正确的结果呢:

因为not in 等价于 不等于集合的所有元素

a not in(10,20,null)
-- 等价于
a != 10 and a!=20 and a!=null
-- 而a!=null 这个条件永远为假 ,因为判断一个值等不等于空值,
--不能使用等于或者不等于,因为永远是不等于。

8f4979bbce5643ba80e9ed7278eab20b.png1ab74d3225ca441e9cb25042eaaf122c.pngfab6473152b54e5eab2f918725f2a44c.png

因此多行子查询中如果存在空值,就不能使用not in 。但是如果子查询的结果包含空值,是可以使用in,因为这里in等同于any,any是取集合当中的一个值,不用和集合中的所有值进行比较。

在多行子查询当中,且包含空值,使用not in 的正确写法如下:


select *
from emp
where empno not in( 
          select mgr
          from emp
          where mgr is not null)


dc6fc439a5764428a1a352d2c7307329.png


相关文章
|
23天前
|
Cloud Native 关系型数据库 分布式数据库
阿里云牵手海亮科技,共建“教育科技数据库创新应用中心”
海亮科技选择引入阿里云PolarDB开源分布式版(PolarDB for Xscale)数据库,不仅能解决海亮科技数据库业务中面临的可靠性、稳定性问题,也为海亮科技业务的高速发展提供了更好的灵活性和可扩展性。
|
1天前
|
Cloud Native 关系型数据库 分布式数据库
阿里云牵手海亮科技,共建“教育科技数据库创新应用中心”
近日,阿里云与世界500强旗下、国内领先的教育服务提供商海亮科技集团(以下简称“海亮科技”)达成合作,联合成立“教育科技数据库创新应用中心”。双方将充分整合优势资源,共同推进教育科技领域的数据库技术研究和国产数据库的应用与发展。
19 1
|
27天前
|
存储 C# 关系型数据库
“云端融合:WPF应用无缝对接Azure与AWS——从Blob存储到RDS数据库,全面解析跨平台云服务集成的最佳实践”
【8月更文挑战第31天】本文探讨了如何将Windows Presentation Foundation(WPF)应用与Microsoft Azure和Amazon Web Services(AWS)两大主流云平台无缝集成。通过具体示例代码展示了如何利用Azure Blob Storage存储非结构化数据、Azure Cosmos DB进行分布式数据库操作;同时介绍了如何借助Amazon S3实现大规模数据存储及通过Amazon RDS简化数据库管理。这不仅提升了WPF应用的可扩展性和可用性,还降低了基础设施成本。
54 0
|
27天前
|
数据库 C# 开发者
WPF开发者必读:揭秘ADO.NET与Entity Framework数据库交互秘籍,轻松实现企业级应用!
【8月更文挑战第31天】在现代软件开发中,WPF 与数据库的交互对于构建企业级应用至关重要。本文介绍了如何利用 ADO.NET 和 Entity Framework 在 WPF 应用中访问和操作数据库。ADO.NET 是 .NET Framework 中用于访问各类数据库(如 SQL Server、MySQL 等)的类库;Entity Framework 则是一种 ORM 框架,支持面向对象的数据操作。文章通过示例展示了如何在 WPF 应用中集成这两种技术,提高开发效率。
38 0
|
27天前
|
NoSQL 关系型数据库 MySQL
|
27天前
|
开发者 存储 API
Xamarin 开发者的社区资源概览:从官方文档到GitHub示例,全面探索提升开发技能与解决问题的多元化渠道与实用工具
【8月更文挑战第31天】Xamarin 开发者社区资源概览旨在提升开发效率与解决问题,涵盖官方文档、社区论坛、GitHub 项目等。官方文档详尽,涵盖 Xamarin.Forms 使用、性能优化等;社区论坛供交流心得;GitHub 提供示例代码。此外,第三方博客、视频教程及 Xamarin University 等资源也丰富多样,适合各阶段开发者学习与提升。通过综合利用这些资源,开发者可不断进步,应对技术挑战。
33 0
|
27天前
|
存储 数据管理 数据库
|
27天前
|
Java 前端开发 Spring
技术融合新潮流!Vaadin携手Spring Boot、React、Angular,引领Web开发变革,你准备好了吗?
【8月更文挑战第31天】本文探讨了Vaadin与Spring Boot、React及Angular等主流技术栈的最佳融合实践。Vaadin作为现代Java Web框架,与其他技术栈结合能更好地满足复杂应用需求。文中通过示例代码展示了如何在Spring Boot项目中集成Vaadin,以及如何在Vaadin项目中使用React和Angular组件,充分发挥各技术栈的优势,提升开发效率和用户体验。开发者可根据具体需求选择合适的技术组合。
32 0
|
27天前
|
SQL 关系型数据库 数据处理
|
27天前
|
存储 SQL NoSQL
探索数据存储的多样性:深入比较Entity Framework Core与NoSQL数据库MongoDB的特性与应用
【8月更文挑战第31天】在现代软件开发中,选择合适的数据存储方案对应用性能至关重要。本文通过对比Entity Framework Core(EF Core)和MongoDB,探讨两者的特点及适用场景。EF Core作为.NET生态中的ORM,简化了SQL数据库的交互;MongoDB则是一种灵活的NoSQL文档数据库,适合处理大量非结构化数据。两者在数据模型、查询方式及性能上各有优势,选择时需根据具体应用需求决定。理解这些差异有助于做出更合理的技术选型。
30 0