前言

sql的嵌套查询可以说是sql语句中比较复杂的一部分,但是掌握好了的话就可以提高查询效率。下面将介绍带in的子查询、带比较运算符的子查询、带any/all的子查询、带exists的子查询以及基于派生表的子查询。很多数据库是不区分关键字大小写的,并且关键字还会有高亮,所以我为了写语句方便(不要频繁切换大小写或者按shift键)和看着方便(大写一般还要在大脑中转换下)关键字是使用小写。

什么是SQL嵌套查询

嵌套查询指的是一个查询语块可以嵌套在另外一个查询语句块的where子句或者having子句中,前者为子查询或内查询,后者为父查询或外查询。

表的定义

例子使用的表的定义为:

create table `student`(
`sno` char(12) collate utf8_bin not null primary key comment '学号',
`sname` char(30) collate utf8_bin not null comment '姓名',
`birthday` Date collate utf8_bin comment '出生日期'
)engine=InnoDB default charset=utf8 collate=utf8_bin comment '学号信息表'; create table `course`
(
`cno` char(4) collate utf8_bin not null primary key comment '课程号',
`cname` char(40) collate utf8_bin not null comment '课程名',
`ceredit` smallint not null default 0 comment '学分'
)engine=InnoDB default charset=utf8 collate=utf8_bin comment '课程表'; create table `sc`
(
`sno` char(12) collate utf8_bin not null comment '学号',
`cno` char(4) collate utf8_bin not null comment '课程号',
`score` smallint not null default 0 comment '成绩'
)engine=InnoDB default charset=utf8 collate=utf8_bin comment '学生课程表';
#为sc表添加主键和外键
alter table `sc` add primary key (`sno`,`cno`);
alter table `sc` add foreign key(`sno`) references `student`(`sno`);
alter table `sc` add foreign key(`cno`) references `course`(`cno`);

带in的子查询

in关键字主要用于判断表达式是否在多值列表中。返回在多值列表中的记录。

#列出选修了C001课程的学生的学号、姓名
select sno, sname
from student
where sno in (select sno from sc where cno='C001');

这里子查询里面没有依赖父查询,此种查询也叫做不相关子查询

若子查询条件依赖于父查询,则为相关子查询

带比较运算符的子查询

带比较运算符的子查询指父查询与子查询之间通过比较运算符连接,并且子查询返回的是单值,才可以用 = 、<、 >、 != 、>=、 <=等比较运算符连接。

#选出学号为2016110129的同学所选课程中的成绩大于他平均成绩的课程的课程号
select cno from sc as x
where score >
(
select avg(score) from sc as y where x.sno=y.sno and x.sno = '2016110129'
)
and sno = '2016110129';

这个子查询依赖于父查询,属于相关子查询

因为这里将同一张表既作为父查询的表又作为子查询的表,所以将这张表取了两个别名,以便区分。

【查询过程】:将父查询中的sno代入子查询中sno进行匹配,然后判断该记录中的课程成绩是否大于该学生的平均成绩,符合条件则返回该记录,否则继续在子查询中匹配该学生的下一条记录。

带any(some)或all的子查询

子查询返回单值时的比较,可以用上面的比较运算符,当返回多值时需要比较,就要使用any(some)或者all。

若是在与多值序列的比较中,只需要满足与多值序列中的一个值满足比较关系就返回true,则用any(some)。

若是在与多值序列的比较中,需要满足与多值序列中的全部值满足比较关系才返回true,则用all。

#查询选课人数最多的课程号
select cno from sc
group by cno
having COUNT(*) >= all(select COUNT(*) from sc group by cno);

【查询过程】:将sc表中的记录按照cno进行分组,筛选记录数最多的课程号。

 all(select COUNT(*) from sc group by cno)

是找出所有以cno分组的记录数,是一个多值集合。使用>=也就是选出最大的值。

带exists的子查询

exists代表存在量词,带有EXISTS的子查询不返回任何数据,只产生逻辑真值“true”或者逻辑假值“false”

使用exists的嵌套语句,若子查询结果不为空,则exists返回true,否则返回false。

使用exists引出的子查询,其目标表达式列都使用*,因为带exists的子查询只返回真值或假值,给出列名无实际含义。

#列出选修了C001课程的学生的学号、姓名
select sno,sname from student
where exists(
select * from sc where sc.sno=student.sno and cno='C001'
);

【查询过程】:从student的第一条记录开始查询,将第一条记录代入子查询中,在sc表中匹配该学生选课记录,若匹配到则立刻返回真,父查询中输出该记录;若匹配完后结果仍为空,否则返回假,继续父查询继续代入下一条记录到子查询中查询。

与in子查询的区别
在带in的子查询中,会遍历sc表中所有记录进行筛选,带exists的查询找到一条记录就返回,不会遍历整个表,所以带EXISTS的查询是一个优质查询。

附加一题作为exists的练习
“查询选了所有课程的学生”

这里需要使用双层带not exists(即不存在)关键词的查询。具体查询语句如下:

#查询选了所有课程的学生
select sno,sname from student where not exists(
select * from course where not exists (
select * from sc where sc.sno=student.sno and sc.cno=course.cno
)
);

这个相当于一个进行一个双重循环,因为是选出学生的信息,所以student表作为“外层循环”,course表作为“内循环”,在sc表中查询学生的选课记录是否存在。

把student表中第一个学生代入“内循环”,然后开始,在sc表中查询该学生是否选了course表中所有课程。

如果遍历了course表后,不存在没有被选的课程(课程在sc表中没有记录),则说明该学生选了所有课程,内部not exists就会返回假,外部not exists返回为真,说明该学生不存在没有选的课程,外部查询输出该学生的信息,然后开始下一个学生的查询。

在遍历course表时,若有一个课程没有被选,则内部就会立刻返回真(不会继续看下一门课程是否被选),外部查询返回为假,说明该学生没有选完所有课程,外部查询就会开始下一个学生的查询。

再附加一个练习
“找出被所有学生选了的课程的课程号和课程名”

select cno,cname from course where not exists(
select * from student where not exists (
select * from sc where sc.sno=student.sno and sc.cno=course.cno
)
);

基于派生表的查询

select 查询的结果也是一张表,可以作为出现在from子句后面作为派生表进行查询。

#求学分获得8分以上学生的学号 平均分  以及总学分
#需要注意此处的作用域不同,只有该课程的成绩大于60才会获得该课程的学分,平均分包括了所有课程(不及格和及格)
#思路:先将查询到的总学分结果看做是一张表 再与sc表连接进行查询平均分
select sc.sno,total_cre,avg(score) from
(select sno,SUM(ceredit) as total_cre from sc,course where sc.cno=course.cno
and score >= 60
group by sno
having SUM(ceredit) >= 8) as temptable, sc
where temptable.sno=sc.sno
group by sc.sno,sum_cre;

小结

回顾了学习数据库时的嵌套查询,简单总结了一番。当时觉得其中比较难理解的exists查询,现在梳理了一下理解起来也没有那么困难。sql语句还是要常写,不然一些逻辑复杂点的语句就会理解不到。

SQL——嵌套查询与子查询的更多相关文章

  1. Linq to SQL 语法查询(链接查询,子查询 & in操作 & join,分组统计等)

    Linq to SQL 语法查询(链接查询,子查询 & in操作 & join,分组统计等) 子查询 描述:查询订单数超过5的顾客信息 查询句法: var 子查询 = from c i ...

  2. SQL编程之高级查询(子查询)以及注意事项

    SQL编程之高级查询(子查询)以及注意事项   1.什么是子查询? 当一个查询是另一个查询的条件时,称之为子查询.子查询可以使用几个简单命令构造功能强大的复合命令.子查询最常用于SELECT-SQL命 ...

  3. Sql Server的艺术(六) SQL 子查询,创建使用返回多行的子查询,子查询创建视图

    子查询或内部查询或嵌套查询在另一个SQL查询的查询和嵌入式WHERE子句中. 子查询用于返回将被用于在主查询作为条件的数据,以进一步限制要检索的数据. 子查询可以在SELECT,INSERT,UPDA ...

  4. Server Sql 多表查询、子查询和分页

    一.多表查询:根据特定的连接条件从不同的表中获取所需的数据 多表查询语法: SELECT table1.column, table2.column FROM table1, table2 WHERE ...

  5. SQL Server 基础:子查询

    1.子查询的概念:子查询就是嵌套在主查询中的查询.子查询可以嵌套在主查询中所有位置,包括SELECT.FROM.WHERE.GROUP BY.HAVING.ORDER BY.2.子查询的分类:2.1按 ...

  6. SQL Server 基础 05 多链表查询和子查询

     连接查询 值得注意的是:字段前必须加表名,以便混淆 -- 多表连接查询和子查询 select * from dbo.stu_info ,dbo.sname2 -- 加连接规则的查询 where se ...

  7. SQL基本查询_子查询(实验四)

    SQL基本查询_子查询(实验四) 1.查询所有员工中薪水低于"孙军"的员工姓名和薪水: 2.查询与部门编号为"01"的岗位相同的员工姓名.岗位.薪水及部门号: ...

  8. 在论坛中出现的比较难的sql问题:40(子查询 销售和历史库存)

    原文:在论坛中出现的比较难的sql问题:40(子查询 销售和历史库存) 最近,在论坛中,遇到了不少比较难的sql问题,虽然自己都能解决,但发现过几天后,就记不起来了,也忘记解决的方法了. 所以,觉得有 ...

  9. 在论坛中出现的比较难的sql问题:7(子查询 判断某个字段的值是否连续)

    原文:在论坛中出现的比较难的sql问题:7(子查询 判断某个字段的值是否连续) 最近,在论坛中,遇到了不少比较难的sql问题,虽然自己都能解决,但发现过几天后,就记不起来了,也忘记解决的方法了. 所以 ...

随机推荐

  1. Nuxt.js 从入门到放弃

    Nuxt 是 Vue 上的 SSR,也就是服务端渲染应用框架,可在很大程度上解决当前 SPA 和 CSR 的首页加载慢,不利于 SEO 的问题.本场 Chat 就将详细介绍 Nuxt 的使用以及相关概 ...

  2. VUE-利用OSS BrowserJS-SDK实现阿里OSS前端上传

    项目中遇到利用阿里OSS上传文件,线上很多示例用到了各种SDK,却没有看到OSS BrowserJS-SDK相关示例,鉴于脑子不好使,记一下. 封装upload相关组件  使用npm安装SDK的开发 ...

  3. centOS7上编译hadoop-2.7.7

    一.阅读编译文档 在hadoop源码包根目录下有个一个BUINDING.txt的文件,文件说明了编译hadoop所需要的一些编译hadoop所需要的一些编译环境相关的东西.不同hadoop版本的要求都 ...

  4. create-react-app创建的项目中registerServiceWorker.js文件的作用

    使用React官方的脚手架工具create-react-app创建的项目,目录中会存在registerServiceWorker.js这个文件,这个文件的作用是什么呢? 这个文件可以使用也可以不使用, ...

  5. c# 钩子类

    using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using S ...

  6. Python 爬虫入门(二)——爬取妹子图

    Python 爬虫入门 听说你写代码没动力?本文就给你动力,爬取妹子图.如果这也没动力那就没救了. GitHub 地址: https://github.com/injetlee/Python/blob ...

  7. [Swift]LeetCode101. 对称二叉树 | Symmetric Tree

    Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center). For e ...

  8. [Swift]LeetCode188. 买卖股票的最佳时机 IV | Best Time to Buy and Sell Stock IV

    Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...

  9. Python档案袋( 面向对象 )

    类即是一个模型,根据模型建立起不同的对象,对象间拥有共同的一些属性 简单的类: class P: #类变量,所有实例共享变量,推荐使用方法是:类名.类变量名 pvarx="ppvar1&qu ...

  10. 使用xUnit为.net core程序进行单元测试 -- Assert

    第一部分: http://www.cnblogs.com/cgzl/p/8283610.html Assert Assert做什么?Assert基于代码的返回值.对象的最终状态.事件是否发生等情况来评 ...