第3章 关系数据库标准语言SQL——3.4 数据查询(下)

简介: 第3章 关系数据库标准语言SQL——3.4 数据查询(下)

3.4  数据查询(下)


3.4.3  嵌套查询


     在SQL语言中,一个select-from-where语句称为一个查询块。将一个查询块嵌套在另一个查询块的where子句或having短语的条件中的查询称为嵌套查询(nested query)。


例如:

 

select Sname                      /*外层查询或父查询*/
from Student
where Sno in
        (select Sno                 /*内层查询或子查询*/
        from SC
        where Cno = ‘2’);

     本例中,下层查询块select Sno from where Cno = ‘2’是嵌套在上层查询块select Sname from Student where Sno in的where条件中的。

     上层的查询块称为外层查询或父查询,下层查询块称为内层查询或子查询。

     SQL语言允许多层嵌套查询,即一个子查询中还可以嵌套其他子查询。需要特别指出的是,子查询的select语句中不能使用order by子句,order by子句只能对最终查询结果排序。     嵌套查询使用户可以用多个简单查询构成复杂的查询,从而增强SQL的查询能力。以层层嵌套的方式来构造程序正是SQL中“结构化”的含义所在。


01 带有in谓词的子查询


     在嵌套查询中,子查询的结果往往是一个集合,所以谓词in是嵌套查询中最经常使用的谓词。


例3.55  查询与“刘晨”在同一个系学习的学生。


先分步来完成此查询,然后再构造嵌套循环。


①确定“刘晨”所在系名

select Sdept from Student where Sname = ‘刘晨’;

结果为CS。


②查找所有在CS系学习的学生。

select Sno,Sname,Sdept from Student where Sdept = ‘CS’;


结果为

Sno Sname Sdept
201215121 李勇 CS
201215122 刘晨 CS


     将第一步查询嵌入到第二步查询的条件中,构造嵌套查询如下:


select Sno,Sname,Sdept        /*例3.55的解法一*/
from Student
where Sdept in(
        select Sdept
        from Student
        where Sname = ‘刘晨’);


     本例中,子查询的查询条件不依赖于父查询,称为不相关子查询。

     本例中的查询也可以用自身连接来完成:


select S1.Sno,S1.Sname,S1.Sdept     /*例3.55的解法二*/
from Student S1,Student S2
where S1.Sdept = S2.Sdept and S2.Sname = ‘刘晨’;

例3.56  查询选修了课程名为“信息系统”的学生学号和姓名。

select Sno,Sname
from Student
where Sno in
        (select Sno
        from SC
        where Cno in
                (select Cno
                from Course
                where Cname = ‘信息系统’
                )
        );

本查询同样可以用连接查询实现:


select Student.Sno,Sname
from Student,SC,Course
where Student.Sno = SC.Sno and
         SC.Cno = Course.Cno and
         Course.Cname = ‘信息系统’;

      有些嵌套查询可以用连接运算替代,有些是不能替代的。从例3.55和例3.56可以看到,查询涉及多个关系时,用嵌套查询逐步求解层次清楚,易于构造,具有结构化程序设计的优点。但是相比于连接运算,目前商用关系数据库管理系统对嵌套查询的优化做得还不够完善,所以在实际应用中,能够用连接运算表达的查询尽可能采用连接运算。

       

      例3.55和例3.56中子查询的查询条件不依赖于父查询,这类子查询称为不相关子查询。不相关子查询是较简单的一类子查询。如果子查询的查询条件依赖于父查询,这类子查询称为相关子查询(correlated subquery),整个查询语句称为相关嵌套查询(correlated nested query)语句。


02 带有比较运算符的子查询


     带有比较运算符的子查询是指父查询与子查询之间用比较运算符进行连接。当用户能确切知道内层查询返回的是单个值时,可以用>、<、=、>=、<=、!=或<>等比较运算符。


例3.57  找出每个学生超过他自己选修课程平均成绩的课程号。

select Sno,Cno
from SC x
where Grade >= (
        select avg(Grade)
        from SC y
        where y.Sno = x.Sno);


     x是表SC的别名,又称为元组变量,可以用来表示SC的一个元组。内层查询时求一个学生所有选修课程平均成绩的,至于是哪个学生的平均成绩要看参数x.Sno的值,而该值是与父查询相关的,因此这类查询称为相关子查询


     求解相关子查询不能像求解不相关子查询那样一次将子查询求解出来,然后求解父查询。内层查询由于与外层查询有关,因此必须反复求值。



03 带有any(some)或all谓词的子查询

     子查询返回单值时可以用比较运算符,但返回多指时要用any(有的系统用some)或all谓词修饰符。而使用any或all谓词时则必须同时使用比较运算符


其语义如下所示:


>any                           大于子查询结果中的某个值

>all                             大于子查询结果中的所有值

<any                           小于子查询结果中的某个值

<all                             小于子查询结果中的所有值

>=any                         大于等于子查询结果中的某个值

>=all                           大于等于子查询结果中的所有值

<=any                         小于等于子查询结果中的某个值

<=all                           小于等于子查询结果中的所有值

=any                           等于子查询结果中的某个值

=all                             等于子查询结果中的所有值(通常没有实际意义)

!=(<>)any               不等于子查询结果中的某个值

!=(<>)all                 不等于子查询结果中的任何一个值


例3.58  查询非计算机科学系中比计算机科学系任意一个学生年龄小的学生姓名和年龄。


select Sname,Sage
from Student
where Sage < any(
        select Sage
        from Student
        where Sdept = ‘CS’)
and Sdept <> ’CS’           /*注意这是父查询块中的条件*/


结果如下:

Sname Sage
王敏 18
张立 19


     本查询也可以用聚集函数来实现,首先用子查询找出CS系中最大年龄(20),然后在父查询中查所有非CS系且年龄小于20岁的学生。SQL语句如下:


select Sname,Sage
from Student
where Sage < (
        select MAX(Sage)
        from Student
        where Sdept = ‘CS’)
and Sdept <> ‘CS’;


例3.59  查询非计算机科学系中比计算机科学系所有学生年龄都小的学生姓名及年龄。


select Sname,Sage
from Student
where Sage < all(
        select Sage
        from Student
        where Sdept = ‘CS’)
and Sdept <> ‘CS’;


查询结果为:

Sname Sage
王敏 18


     本查询同样也可以用聚集函数实现。SQL语句如下:

select Sname,Sage
from Student
where Sage < (
        select MIN(Sage)
        from Student
        where Sdept = ‘CS’)
and Sdept <> ‘CS’;

     事实上,用聚集函数实现子查询通常比直接用any或all查询效率要高。any、all与聚集函数的对应关系如表3.7所示。


3.7  any(或some)、all谓词与聚集函数、in谓词的等价转换关系


=

<>!=

<=

>=

any

in

-

<max

<=max

>min

>=min

all

-

not in

<min

<=min

>max

>=max


     表3.7中,=any等价于in谓词,<any等价于<max,<>all等价于not in谓词,<all等价于<min,等等。


04 带有exists谓词的子查询

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


例3.60  查询所有选修了1号课程的学生姓名。

select Sname
from Student
where exists (
        select *
        from SC
        where Sno = Student.Sno and 
                Cno = ‘1’);


     使用存在量词exists后,若内层查询结果非空,则外层的where子句返回真值,否则返回假值。

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

      与exists谓词相对应的是not exists谓词。使用存在量词not exists后,若内层查询结果为空,则外层的where子句返回真值,否则返回假值。


例3.61  查询没有选修1号课程的学生姓名。

select Sname
from Student
where not exists (
            select *
            from SC
           where Sno = Student.Sno and 
                Cno = ‘1’);



       些带exists或not exists谓词的子查询不能被其他形式的子查询等价替换,但所有带in谓词、比较运算符、any和all谓词的子查询都能用带exists谓词的子查询等价替换。



例如带in谓词的例3.55可以用如下带exists谓词的子查询替换:

select Sno,Sname,Sdept         /*例3.55的解法四*/
from Student S1
where exists(
        select *
        from Student S2
        where S2.Sdept= S1.Sdept and
                S2.Sname = ‘刘晨’);


例3.62  查询选修了全部课程的学生姓名。

SQL中没有全称量词(for all),但是可以把带有全称量词的谓词转换为等价的带有存在量词的谓词:9bada896b56e87321d5acb7cfbbe25c1_640_wxfrom=5&wx_lazy=1&wx_co=1.jpg

     由于没有全称量词,可将题目的意思转换成等价的用存在量词的形式:查询这样的学生,没有一门课程是他不重修的。其SQL语句如下:

select Sname
from Student
where not exists (
        select *
        from Course
        where not exists (
                select *
                from SC
                where Sno = Student.Sno and 
                        Cno = Course.Cno));


例3.63  查询至少选修了学生201215122选修的全部课程的学生号码。

本查询可以用逻辑蕴涵来表达:查询学号为x的学生,对所有的课程y,只要201215122学生选修了课程y,则x也选修了y。形式化表示如下:

p表示谓词学生201215122”选修了课程y

q表示谓词学生x选修了课程y”

则上述查询为509b4a95b19f25c6338b349c4023f2e4_640_wxfrom=5&wx_lazy=1&wx_co=1.jpg

SQL语言中没有蕴涵(implication)逻辑运算,但是可以利用谓词演算将一个逻辑蕴涵的谓词等价转换为cf843c5c917cf6e3d6cb1e8f2d1324e4_640_wxfrom=5&wx_lazy=1&wx_co=1.jpg

该查询可以转换为如下等价形式:

12b5318762ea387a8a434e3adcc5c9bd_640_wxfrom=5&wx_lazy=1&wx_co=1.jpg


它所表达的语义为:不存在这样的课程y,学生201215122选修了y,而学生x没有选。用SQL语言表示如下:

select distinct Sno
from SC SCX
where not exists 
        (select *
        from SC SCY
        where SCY.Sno = ‘201215122’ and
        not exists
                (select *
                from SC SCZ
                where SCZ.Sno = SCX.Sno and
                    SCZ.Cno = SCY.Cno
                )
        );


3.4.4  集合查询


     select语句的查询结果是元组的集合,所以多个select语句的结果可进行集合操作。集合操作主要包括并操作union、交操作intersect和差操作except。



      注意:参加集合操作的各查询结果的列数必须相同;对应项的数据类型也必须相同。



例3.64  查询计算机科学系的学生及年龄不大于19岁的学生。

select *
from Student
where Sdept = ‘CS’
union
select *
from Student
where Sage <= 19;



       本查询实际上是求计算机科学系的所有学生与年龄不大于19岁的学生的并集。使用union将多个查询结果合并起来时,系统会自动去掉重复元组。如果要保留重复元组则用union all操作符。



例3.65  查询选修了课程1或者选修了课程2的学生。

select Sno
from SC
where Cno = ‘1’
union
select Sno
from SC
where Cno = ‘2’;


例3.66  查询计算机科学系的学生与年龄不大于19岁的学生的交集。

select *
from Student
where Sdept = ‘CS’
intersect
select *
from Student
where Sage <= 19;

这实际上就是查询计算机科学系中年龄不大于19岁的学生。


select * from Student
where Sdept = ‘CS’ and
Sage <= 19;


例3.67  查询既选修了课程1又选修了课程2的学生。就是查询选修课程1的学生集合与选修课程2的学生集合的交集。

select Sno
from SC
where Cno = ‘1’
intersect
select Sno
from SC
where Cno = ‘2’;


本例也可以表示为

select Sno from SC
where Cno = ‘1’ and Sno in
        (select Sno
        from SC
        where Cno = ‘2’);


例3.68  查询计算机科学系的学生与年龄不大于19岁的学生的差集。

select *
from Student
where Sdept = ‘CS’
except
select *
from Student
where Sage <= 19;


也就是查询计算机科学系中年龄大于19岁的学生。

select * from Student
where Sdept = ‘CS’ and Sage > 19;


3.4.5  基于派生表的查询


     子查询不仅可以出现在where子句中,还可以出现在from子句中,这时子查询生成的临时派生表(derived table)成为主查询的查询对象。


例如,例3.57找出每个学生超过他自己选修课程平均成绩的课程号,也可以用如下的查询完成:

select Sno,Cno
from SC,(select Sno,avg(Grade) from SC group by Sno)
                as Avg_sc(avg_sno,avg_grade)
        where SC.Sno = Avg_sc.avg_sno and
        SC.Grade >= Avg_sc.avg_grade;


     这里from子句中的子查询将生成一个派生表Avg_sc。该表由avg_sno和avg_grade两个属性组成,记录了每个学生的学号及平均成绩。主查询将SC表与Avg_sc按学号相等进行连接,选出选修课成绩大于其平均成绩的课程号。

     如果子查询中没有聚集函数,派生表可以不指定属性列,子查询select子句后面的列名为其默认属性。


例如例3.60查询所有选修了1号课程的学生姓名,可以用如下查询完成:

select Sname
from Student,(select Sno from SC where where Cno = ‘1’) as SC1
where Student.Sno = SC1.Sno;


     需要说明的是,通过from子句生成派生表时,as关键字可以省略,但必须为派生关系指定一个别名。而对于基本表,别名是可选择项。


3.4.6  select语句的一般格式


select语句的一般格式:

select [all|disinct] <目标列表达式> [别名] [,<目标列表达式> [别名]]···

from <表名或视图名> [别名] [,<表名或视图名>[别名]]···|(<select语句>) [as] <别名>

[where <条件表达式>]

[group by <列名1> [having <条件表达式>]]

[order by <列名2> [asc|desc]];


01 目标列表达式的可选格式

     (1) *

     (2)<表名>.*

     (3)count([distinct|all] *)

     (4)[<表名>.]<属性列名表达式> [,[<表名>.] <属性列名表达式>]···

     其中,<属性列名表达式>可以是由属性列、作用于属性列的聚集函数和常量的任意算术运算(+,-,*,/)组成的运算公式。


02 聚集函数的一般格式

3deaea21819c719705b554af3132cef6_640_wxfrom=5&wx_lazy=1&wx_co=1.jpg


03 where子句的条件表达式的可选格式

1

fee167b63ac587120b96d826def3eeb6_640_wxfrom=5&wx_lazy=1&wx_co=1.jpg


2

7ea7f89e10dd2cc08305b415103c7087_640_wxfrom=5&wx_lazy=1&wx_co=1.png


3

b660b88e87601e6d6c58ddb1e8686166_640_wxfrom=5&wx_lazy=1&wx_co=1.jpg


4

<属性列名>  [not]  like  <匹配串>


5

<属性列名>  is  [not]  null


6

[not]  exists  (select语句)


7

37301037039ce49f318b35aee3af9476_640_wxfrom=5&wx_lazy=1&wx_co=1.jpg


相关文章
|
24天前
|
SQL 开发框架 .NET
ASP.NET连接SQL数据库:详细步骤与最佳实践指南ali01n.xinmi1009fan.com
随着Web开发技术的不断进步,ASP.NET已成为一种非常流行的Web应用程序开发框架。在ASP.NET项目中,我们经常需要与数据库进行交互,特别是SQL数据库。本文将详细介绍如何在ASP.NET项目中连接SQL数据库,并提供最佳实践指南以确保开发过程的稳定性和效率。一、准备工作在开始之前,请确保您
112 3
|
6天前
|
SQL 数据采集 监控
局域网监控电脑屏幕软件:PL/SQL 实现的数据库关联监控
在当今网络环境中,基于PL/SQL的局域网监控系统对于企业和机构的信息安全至关重要。该系统包括屏幕数据采集、数据处理与分析、数据库关联与存储三个核心模块,能够提供全面而准确的监控信息,帮助管理者有效监督局域网内的电脑使用情况。
12 2
|
23天前
|
SQL Oracle 关系型数据库
SQL语言的主要标准及其应用技巧
SQL(Structured Query Language)是数据库领域的标准语言,广泛应用于各种数据库管理系统(DBMS)中,如MySQL、Oracle、SQL Server等
|
24天前
|
SQL 监控 数据库
慢SQL对数据库写入性能的影响及优化技巧
在数据库管理系统中,慢SQL(即执行缓慢的SQL语句)不仅会影响查询性能,还可能对数据库的写入性能产生显著的不利影响
|
24天前
|
SQL 数据库 数据库管理
数据库SQL函数应用技巧与方法
在数据库管理中,SQL函数是处理和分析数据的强大工具
|
12天前
|
SQL 数据库
SQL数据库基础语法入门
[link](http://www.vvo.net.cn/post/082935.html)
|
23天前
|
SQL 存储 监控
串口调试助手连接SQL数据库的技巧与方法
串口调试助手是电子工程师和软件开发人员常用的工具,它能够帮助用户进行串口通信的调试和数据分析
|
23天前
|
SQL 存储 数据采集
如何把问卷录入SQL数据库
将问卷数据录入SQL数据库是一个涉及数据收集、处理和存储的过程
|
24天前
|
SQL 开发框架 .NET
ASP.NET连接SQL数据库:实现过程与关键细节解析an3.021-6232.com
随着互联网技术的快速发展,ASP.NET作为一种广泛使用的服务器端开发技术,其与数据库的交互操作成为了应用开发中的重要环节。本文将详细介绍在ASP.NET中如何连接SQL数据库,包括连接的基本概念、实现步骤、关键代码示例以及常见问题的解决方案。由于篇幅限制,本文不能保证达到完整的2000字,但会确保
|
25天前
|
SQL 存储 数据库
慢SQL对数据库写入性能的影响及优化技巧
在数据库管理系统中,慢SQL(即执行缓慢的SQL语句)不仅会影响查询性能,还可能对数据库的写入性能产生显著的不利影响