3)ORDER BY排序语句
通常,查询的结果是以无序的方式显示的,有时需要将查询结果按照一定次序来进行排序。ORDER BY就可以用上了,例如查询课程号为202的课程成绩的所有信息,并按照成绩降序排列
SELECT *
FROM SC
WHERE Cno = '202'
ORDER BY Grade DESC;(ASC代表升序,没有按ASC处理)
本来这个语句超简单,但是这货有个奇葩的共能就是能指定多个排序列,我TM……,比如这种:
SELECT *
FROM SC
WHERE Cno = '202'
ORDER BY Cno,Grade DESC;(经过查证,并非出现两个查询结果,而是先按照第一个排序规则排列,在第一个相同的情况下再按照下一个规则排序)
4)SQL函数
COUNT 计数函数,基本形式 COUNT ([ALL|DISTINCT] *)用于返回查询结果元组的所有的个数或者不重复的个数。例如查询女生的数量
SELECT COUNT (*)
FROM Student
WHERE Sex = '女';
其实还蛮好记忆理解的,可以将COUNT也视为一种属性,即最终结果的个数,反正我就是这么理解的。
除此之外,还有求和SUM、平均值AVG、最大值MAX、最小值MIN等函数,基本形式与COUNT完全相同:<函数名称> ([ALL|DISTINCT] <值表达式>),所谓值表达式一般是指属性,比如查询数据结构课程的成绩平均值:
SELECT AVG (Grade)
FROM SC
WHERE Cname = '数据结构';
5)GROUP BY分组语句
GROUP BY主要是对记录进行分组,然后对每个分组使用聚集函数能够极大地提升效率(聚集函数+GROUP BY会使函数对分组进行相应的计算),其一般形式为:GROUP BY <分组列> {,<分组列>} [HAVING <分组选择条件>],那么HAVING的作用是对分组进行筛选,与WHERE不同,WHERE选择的是记录。例如查询每个学生的平均成绩,并输出平均成绩大于90的学生学号和平均成绩:
SELECT Sno,AVG(Grade)
FROM SC
GROUP BY Sno HAVING AVG(Grade) > 90;
6)连接查询
连接查询可以对多个表进行查询,即在FROM中包括多个表,这表示多个表的笛卡儿积,但是一般来说自然连接会更适合实际情况。例如查询学号为20142480135的学生各科成绩,显示每门课程的课程名和成绩。
SELECT Cname,Grade
FROM SC,Courses
WHERE SC.Cno = Courses.Cno AND SC.Sno = '20142480135';(思考红色部分和自然连接的关系)
自身连接是和自己本身连接,通常情况使用不多,比如查询和武一鸣出生年月相同的学生的姓名:
SELECT B.Sname
FROM Student.A,Student.B
WHERE A.Birthday = B.Birthday AND
S1.Sname = '武一鸣' AND
S2.Sname <> '武一鸣';
用法是不是很奇葩??
7)嵌套查询
嵌套查询将一个查询嵌套在另一个SQL语句中,最常见的嵌套是子查询嵌套在父查询WHERE或者HAVING语句中,其中子查询不能使用ORDER BY子句。嵌套查询可以分两类:不相关子查询和相关子查询,前者子查询的条件不依赖于父查询,后者子查询条件依赖于父查询。嵌套查询表达式可以分为IN表达式、存在表达式、NULL表达式和唯一表达式。
IN表达式好像有点眼熟,在WHERE表达式中判断是否在集合中会用到IN,复习一下:
SELECT Sno,Sname
FROM Student
WHERE Speciality IN (‘计算机科学与技术’,‘软件工程’);
显然IN后面要紧跟一个集合,之前使用的都是显性的集合,实际上集合还可以是通过查询语句查询到的集合,例如
SELECT Sno,Sname
FROM Student
WHERE Speciality IN (
SELECT Speciality
FROM Student
WHERE Sname = '武一鸣'
);
这里的集合是我的专业,如果我的专业是软件工程,那么这个SQL语句的作用就是查询软件工程所有学生的学号和姓名。当然这是没有人和我重名的情况下,否则就是另一个故事了。如果没人和我重名,代表子查询的结果只有一个值,可以将IN改为=,作用是相同的。这个示例是一个典型的不相关子查询。
SQL还允许将一个元素与子查询的结果集进行比较,这种量化的表达式常用形式是:<值表达式> θ ALL | SOME | ANY <子查询>,其中值表达式通常是属性,θ就是比较运算符,ANY和SOME的意义是一样的,当子查询结果是单个值时,ALL、SOME或者ANY可以省略。注意= SOME等价于IN,这也印证了前面单个值 = 等价于 IN的说法。
比如查询比软件工程专业所有学生都小的其他专业的学生学号、姓名和专业
SELECT Sno,Sname,Speciality
FROM Student
WHERE Birthday > ALL (
SELECT Bithday
FROM Student
WHERE Speciality = '软件工程');(原答案WHERE语句包括Speciality <> '软件工程' ,但是仔细一想其实是不必要的,因为软件工程怎么可能有一个年龄比所有人都小的学生,至少也不会比自己的年龄小)
事实上该语句可以改为:
SELECT Sno,Sname,Speciality
FROM Student
WHERE Birthday > (
SELECT MAX(Bithday)
FROM Student
WHERE Speciality = '软件工程');
聚集函数通常效率上相较于SOME和ALL会更高一些(但不能复合嵌套,例如MAX(AVG(…))的形式),它们的对应关系如下:
存在量词EXISTS
接下来就是整个SQL查询乃至整个SQL中最困难的部分——存在量词(我认为的@_@)。
一般形式:EXISTS <子查询>,接下来我就从EXISTS和IN的区别展开讲解吧。两者的区别主要在于执行顺序的不同,IN是先执行子查询,然后对结果在进行筛选,而EXISTS是先执行父查询,将查询的每个结果代入到子查询中进行检验,如果为TRUE,则保留,否则去除,最终的结果即为所求。
例如查询选修了全部课程的学生的学号和姓名:
SELECT Sno,Sname
FROM Student
WHERE NOT EXISTS (
SELECT *
FROM Courses C
WHERE NOT EXISTS (
SELECT *
FROM SC
WHERE SC.Sno = S.Sno AND SC.Cno = C.Cno ) );
检查子查询结果中的重复元组
UNIQUE <子查询>
查询只讲授一门课程教授的姓名
SELECT Tname
FROM Teacher T
WHERE UNIQUE (
SELECT Tno
FROM Teacher TC
WHERE T.Tno = TC.Tno;)
这句话的逻辑在于对于父查询的每个结果执行子查询,若结果只有一个,那么保留该结果。