SELECT [ALL | DISTINCT] <目标列表达式> [,<目标列表达式>]…
FROM <表名或视图名> [,<表名或视图名>]… |(SELECT语句)[AS] <别名>
[WHERE <条件表达式>]
[GROUP BY <列名1> [HAVING <条件表达式>]]
[ORDER BY <列名2> [ASC | DESC]];
(1)SELECT子句:指定要显示的属性列;
(2)FROM子句:指定查询对象(基本表或视图);
(3)WHERE子句:指定查询条件;
(4)GROUP BY子句:对查询结果按指定列的值分组,该属性列值相等的元组为一个组。通常会在每组中作用聚集函数。
(5)HAVING短语:只有满足指定条件的组才予以输出;
(6)ORDER BY子句:对查询结果表按指定列值的升序或降序排序。
(1)查询指定列
SELECT <列名1>…<,列名n>
FROM 表名;
例子:查询全体学生的学号与姓名。
SELECT Sname,Sno,Sdept
FROM Student;
(2)查询全部列
SELECT * FROM 表名;
(3)查询经过计算的值
①
SELECT子句的<目标列表达式>不仅可以为表中的属性列,也可以是表达式,还可以是字符串常量,函数等。
例子:查全体学生的姓名、出生年份和所在院系,要求用小写字母表示系名。
SELECT Sname,'Year of Birth:',2022-Sage,LOWER(Sdept)
FROM Student;
②
使用列别名改变查询结果的列标题。
例子:
SELECT Sname NAME,'Year of Birth:' BIRTH,2022-Sage BIRTHDAY,LOWER(Sdep) DEPARTMENT FROM Student;
通过指定别名来改变查询结果的列标题,对表达含有算术表达式、常量、函数名的目标列表很有用。
(1)消除取值重复的行
SELECT DISTINCT Sno
FROM SC;
①指定DISTINCT关键词,去掉表中重复的行。
②若没有指定DISTINCT关键词,则缺省为ALL。
(2)常用的查询条件
①比较大小
例子1:查询计算机科学系全体学生的名单:
SELECT Sname
FROM Student
WHERE Sdept='CS';
例子2:查询所有年龄在20岁以下的学生姓名及其年龄:
SELECT Sname,Sage
FROM Student
WHERE Sage<20;
②确定范围
BETWEEN…AND…
NOT BETWEEN…AND…
例子:查询年龄在20~23岁(包括20、23)之间的学生的姓名、系别和年龄:
SELECT Sname,Sdept,Sage
FROM Student
WHERE Sage BETWEEN 20 AND 23;
③确定集合
IN <值表>
NOT IN <值表>
例子:查询计算机科学系CS、数学系MA和信息系IS学生的姓名和性别:
SELECT Sname,Ssex
FROM Student
WHERE Sdept IN ('CS','MA','IS');
④字符匹配
[NOT] LIKE ‘<匹配串>’ [ESCAPE ‘<换码字符>’]
a.<匹配串>可以是一个完整的字符串,也可以含有通配符%和_
%(百分号):代表任意长度(长度不可以为0)的字符串;
_(下横线):代表任意单个字符。
b.匹配串为固定字符串
例子:查询学号为201215121的学生的详细情况:
SELECT *
FROM Student
WHERE Sno LIKE '201215121';
c.匹配串为含通配符的字符串
例子:查询所有姓刘的学生姓名、学号和性别:
SELECT Sname,Sno,Ssex
FROM Student
WHERE Sname LIKE '刘%';
d.使用换码字符将通配符转义为普通字符
ESCAPE ’ \ ’ 表示 ’ \ '为换码字符;
匹配字符串中紧跟在“ \ ”后面的字符“ _ ”不再是通配符,转义为普通字符“_”。
例子:查询DB_Design课程的课程号和学分:
SELECT Cno,Ccredit
FROM Course
WHERE Cname LIKE 'DB\_Design' ESCAPE '\';
⑤涉及空值的查询
IS NULL
IS NOT NULL
IS不能用=代替
例子:某些学生选修课程后没有参加考试,所以有选课记录,但没有考试成绩。查询缺少成绩的学生的学号和相应的课程号:
SELECT Sno,Cno
FROM SC
WHERE Grade IS NULL;
⑥多重条件查询
a.AND和OR来连接多个查询条件;
b.AND的优先级高于OR;
c.可以用括号改变优先级。
例子:查询计算机系年龄在20岁以下的学生姓名:
SELECT Sname
FROM Student
WHERE Sdept='CS' AND Sage<20;
(1)可以按一个或多个属性列排序
升序:ASC;
降序:DESC;
缺省值为升序。
(2)对于空值,排序时显示的次序由具体系统实现来决定。
(3)例子:查询选修了3号课程的学生的学号及其成绩,查询结果按分数降序排列:
SELECT Sno,Grade
FROM SC
WHERE Cno='3'
ORDER BY Grade DESC;
WHERE子句中是不能用聚集函数作为条件表达式。
使用HAVING短语替代WHERE。
(1)统计元组个数
COUNT(*)
(2)统计一列中值的个数
COUNT([DISTINCT | ALL] <列名>)
(3)计算一列值的总和(此列必须为数值型)
SUM([DISTINCT | ALL] <列名>)
(4)计算一列值的平均值(此列必须为数值型)
AVG([DISTINCT | ALL] <列名>)
(5)求一列中的最大值和最小值
MAX([DISTINCT | ALL] <列名>)
MIN([DISTINCT | ALL] <列名>)
(6)例子
①查询选修了课程的学生人数:
SELECT COUNT(DISTINCT Sno)
FROM SC;
②计算1号课程的学生平均成绩:
SELECT AVG(Grade)
FROM SC
WHERE Sno='1';
(1)细化聚集函数的作用对象
①如果未对查询结果分组,聚集函数将作用于整个查询结果;
②对查询结果分组后,聚集函数将分别作用于每个组;
③按指定的一列或多列值分组,值相等的为一组。
(2)例子
①求各个课程号及相应的选课人数
SELECT Cno,COUNT(Sno)
FROM SC
GROUP BY Cno;
②查询平均成绩大于等于90分的学生学号和平均成绩:
SELECT Sno,AVG(Grade)
FROM SC
GROUP BY Sno
HAVING AVG(Grade)>=90;
注意:WHERE子句中不能使用聚集函数作为条件表达式,此时需要用HAVING
(3)HAVING短语与WHERE子句的区别:
①作用对象不同;
②WHERE子句作用于基表或视图,从中选择满足条件的元组;
③HAVING短语作用于组,从中选择满足条件的组。
(1)连接查询:同时涉及两个以上的表的查询。
(2)连接条件或连接谓词:用来连接两个表的条件。
[<表名1>.] <列名1> <比较运算符> [<表名2>.] <列名2>
[<表名1>.] <列名1> BETWEEN [<表名2>.] <列名2> AND [<表名2>.] <列名3>
(3)连接字段:连接谓词中的列名称
连接条件中的各连接字段类型必须是可比的,但名字不必相同。(取值于同一个域)
(1)等值连接
连接运算符为 =
例子:查询每个学生及其选修课程的情况:
SELECT Student.*,SC.*
FROM Student,SC
WHERE Student.Sno=SC.Sno;
(2)连接操作的执行过程
①嵌套循环法(NESTED-LOOP)
(类似于双重for循环)
a.首先在表1中找到第一个元组,然后从头开始扫描表2,逐一查找满足连接件的元组,找到后就将表1中的第一个元组与该元组拼接起来,形成结果表中一个元组。
b.表2全部查找完后,再找表1中第二个元组,然后再从头开始扫描表2,逐一查找满足连接条件的元组,找到后就将表1中的第二个元组与该元组拼接起来,形成结果表中一个元组。
c.重复上述操作,直到表1中的全部元组都处理完毕。
②排序合并法(SORT-MERGE)
a.常用于 = 连接;
b.首先按连接属性对表1和表2排序;
c.对表1的第一个元组,从头开始扫描表2,顺序查找满足连接条件的元组,找到后就将表1中的第一个元组与该元组拼接起来,形成结果表中一个元组。当遇到表2中第一条大于表1连接字段值的元组时,对表2的查询不再继续。
d.找到表1的第二条元组,然后从刚才的中断点处继续顺序扫描表2,查找满足连接条件的元组,找到后就将表1中的第一个元组与该元组拼接起来,形成结果表中一个元组。直到遇到表2中大于表1连接字段值的元组时,对表2的查询不再继续。
e.重复上述操作,直到表1或表2中的全部元组都处理完毕为止。
③索引连接(INDEX-JOIN)
a.对表2按连接字段建立索引;
b.对表1中的每个元组,依次根据其连接字段值查询表2的索引,从中找到满足条件的元组,找到后就将表1中的第一个元组与该元组拼接起来,形成结果表中一个元组。
(3)自然连接
SELECT Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade
FROM Student,SC
WHERE Student.Sno=SC.Sno;
(4)一条SQL语句可以同时完成选择和连接查询,这时WHERE子句是由连接谓词和选择谓词组成的复合条件。
例子:查询选修2号课程且成绩在90分以上的所有学生的学号和姓名。
SELECT Student.Sno,Sname
FROM Student,SC
WHERE Student.Sno=SC.Sno AND SC.Cno='2' AND SC.Grade>90;
执行过程:
a.先从SC中挑选出Cno=‘2’并且Grade>90的元组形成一个中间关系;
b.再和Student中满足连接条件的元组进行连接得到最终的结果关系。
(1)自身连接:一个表与其自己进行连接。
(2)需要给表起别名以示区别。
(3)由于所有属性名都是同名属性,因此必须使用别名前缀。
(4)例子:查询每一门课的间接先修课(即先修课的先修课)
SELECT FIRST.Cno,SECOND.Cpno
FROM Course FIRST,COURSE SECOND
WHERE FIRST.Cpno=SECOND.Cno;
(1)外连接与普通连接的区别
①普通连接操作只输出满足连接条件的元组;
②外连接操作以指定表我连接主体,将主体表中不满足连接条件的元组一并输出;
③左外连接:列出左边关系中所有的元组;
④右外连接:列出右边关系中所有的元组。
(2)例子:
SELECT Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade
FROM Student LEFT OUT JOIN SC ON
(Student.Sno=SC.Sno);
(1)多表连接:两个以上的表进行连接。
(2)例子:查询每个学生的学号、姓名、选修的课程名及成绩:
SELECT Student.Sno,Sname,Cname,Grade
FROM Student,SC,Course //多表连接
WHERE Student.Sno=SC.Sno AND SC.Cno=Course.Cno;
(1)一个SELECT-FROM-WHERE语句成为一个查询块;
(2)将一个查询块嵌套在另一个查询块的WHERE子句或HAVING短语的条件中的查询称为嵌套查询。
SELECT Sname //外层查询(父查询)
FROM Student
WHERE Sno IN
(SELECT Sno //内层查询(子查询)
FROM SC
WHERE Cno='2');
(3)上层的查询块称为外层查询或父查询;
(4)下层查询块称为内层查询或子查询;
(5)SQL语言允许多层嵌套查询:
即一个子查询中还可以嵌套其他子查询。
(6)子查询的限制:
不能使用ORDER BY子句,只能对最终查询结果排序。
(1)不相关子查询:子查询的查询条件不依赖与父查询
由里向外逐层处理。
即每个子查询在上一级查询处理之前求解,子查询的结果用于建立其父查询的查找条件。
(2)相关子查询:子查询的查询条件依赖于父查询
a.首先取外层查询中表的第一个元组,根据它与内层查询相关的属性值处理内层查询,若WHERE子句返回值为真,则取此元组放入结果表;
b.然后再取外层表的下一个元组;
c.重复这一过程,直至外层表全部检查完为止。
(1)例子:查询与“刘晨”在同一个系学习的学生的学号、姓名、系名。
step1:确定“刘晨”所在系名
SELECT Sdept
FROM Student
WHERE Sname='刘晨';`
返回CS
step2:查找所有在CS系学习的学生的学号、姓名、系名
SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept='CS';
整合:将第一步查询嵌入到第二步查询的条件中
SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept IN
(SELECT Sdept
FROM Student
WHERE Sname='刘晨');`
该查询为不相关子查询
也可用自身连接来完成:
SELECT S1.Sno,S1.Sname,S1.Sdept
FROM Student S1,Student S2
WHERE S1.Sdept=S2.Sdept
AND S2.Sname='刘晨';
(1)当能确切知道内层查询返回单值时,可用比较运算符。
> < = >= <= != <>
例子:
SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept=
(SELECT Sdept
FROM Student
WHERE Sname='刘晨');
(1)使用ANY或ALL谓词时必须同时使用比较运算。
>ANY 大于子查询结果中的某个值
>ALL 大于子查询结果中的所有值
>= ANY 大于等于子查询结果中的某个值
>= ALL 大于等于子查询结果中的所有值
<= ANY 小于等于子查询结果中的某个值
<= ALL 小于等于子查询结果中的所有值
= ANY 等于子查询结果中的某个值
=ALL 等于子查询结果中的所有值(通常没有实际意义)
!=(或<>ANY 不等于子查询结果中的某个值
!=(或<>ALL 不等于子查询结果中的任何一个值
(2)例子:查询非计算机科学系中比计算机科学系任意一个学生年龄小的学生姓名和年龄
SELECT Sname,Sage
FROM Student
WHERE Sage < ANY
(SELECT Sage
FROM Student
WHERE Sdept='CS')
AND Sdept<>'CS'; //父查询块中的条件
改写为聚集函数实现:
SELECT Sname,Sage
FROM Student
WHERE Sage <
(SELECT MAX(Sage)
FROM Student
WHERE Sdept='CS')
AND Sdept <> 'CS';
(3)ANY(或SOME)、ALL谓词与聚集函数、IN谓词的等价转换关系
(1)EXISTS谓词
①存在量词,符号为 ∃。
②带有EXISTS谓词的子查询不返回任何数据,只产生逻辑真值true或逻辑假值false。
若内层查询结果非空,则外层的WHERE子句返回真值;
若内层查询结果为空,则外层的WHERE子句返回假值。
③由EXISTS引出的子查询,其目标列表达式通常都有*,因为带EXISTS的子查询只返回真值或假值,给出列名无实际意义。
(2)NOT EXISTS谓词
若内层查询结果非空,则外层的WHERE子句返回假值;
若内层查询结果为空,则外层的WHERE子句返回真值。
(3)例子:查询所有选修了1号课程的学生姓名。
思路:
本查询涉及Student和SC关系;
在Student中依次取每个元组的Sno值,用此值去检查SC表;
若SC中存在这样的元组,其Sno值等于此Student.Sno值,并且其Cno=‘1’,则取此Student.Sname送入结果表。
SELECT Sname
FROM Student
WHERE EXISTS
(SELECT *
FROM SC
WHERE Sno=Student.Sno
AND Cno='1');
(4)不同形式的查询间的替换
①一些带EXISTS或NOT EXISTS谓词的子查询不能被其他形式的子查询等价替换;
②所有带IN谓词、比较运算符、ANY和ALL谓词的子查询都能用带EXISTS谓词的子查询等价替换。
(5)用EXISTS/NOT EXISTS实现全称量词
①SQL语言中没有全称量词∀的语法语句;
②通常把带有全称量词的谓词转换为等价的带有存在量词的谓词:
(6)用EXISTS/NOT EXISTS实现逻辑蕴含
①SQL语言中没有蕴含逻辑运算;
(1)并操作UNION
UNION:将多个查询结果合并起来时,系统自动去掉重复元组;
UNION ALL:将多个查询结果合并起来时,保留重复元组。
查询计算机科学系的学生及年龄不大于19岁的学生:
SELECT *
FROM Student
WHERE Sdept='CS'
UNION
SELECT *
FROM Student
WHERE Sage<=19;
(2)交操作INTERSECT
查询计算机科学系的学生及年龄不大于19岁的学生的交集:
SELECT *
FROM Student
WHERE Sdept='CS'
INTERSECT
SELECT *
FROM Student
WHERE Sage<=19;
(3)差操作EXCEPT
查询计算机科学系的学生与年龄不大于19岁的学生的差集:
SELECT *
FROM Student
WHERE Sdept='CS'
EXCEPT
SELECT *
FROM Student
WHERE Sage<=19;
注意:参加集合操作的各查询结果的列数必须相同,对应项的数据类型也必须相同。
(1)子查询不仅可以出现在WHERE子句中,还可以出现在FROM子句中,这时子查询生成的临时派生表(Derived Table)成为主查询的查询对象。
例子:找出每个学生超过他自己选修课程平均成绩的课程号。
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组成*/
(2)如果子查询中没有聚集函数,派生表可以不指定属性列,子查询SELECT子句后面的列名为其缺省属性。
SELECT Sname
FROM Student,
(SELECT Sno
FROM SC
WHERE Cno='1') AS SC1
WHERE Student.Sno=SC1.Sno;
SELECT [ALL|DISTINCT]
<目标列表达式> [别名] [ ,<目标列表达式> [别名]] …
FROM <表名或视图名> [别名]
[ ,<表名或视图名> [别名]] …
|(
(1)*
(2)<表名>.*
(3)COUNT([DISTINCT|ALL]*)
(4) [<表名>.]<属性列名表达式>[,<表名>.]<属性列名表达式>]…
其中<属性列名表达式>可以是由属性列、作用于属性列的聚集函数和常量的任意算术运算(+ - * /)组成的运算公式。