4. 聚集函数
SQL提供的一些聚集函数:
部分聚集函数:
- 如果指定 DISTINCT 短语,则表示在计算时要取消指定列中的重复值。
- 如果不指定DISTINCT短语或指定ALL短语(ALL为默认值),则表示不取消重复值。
例:查询学生总人数
SELECT count(*) FROM student;
例:查询选修了课程的学生人数
学生每选修一门课,在SC中都有一条相应的记录。一个学生要选修多门课程,为避免重复计算学生人数,必须在COUNT函数中用DISTINCT 短语。
SELECT count( DISTINCT Sno) FROM SC;
例:查询3号课程所有学生的成绩总和
当聚集函数遇到空值时,除
COUNT(*)
外,都跳过空值而只处理非空值。COUNT(*)
是对元组进行计数,某个元组的一个或部分列取空值不影响COUNT的统计结果。
SELECT SUM(Grade) FROM SC WHERE Cno = '3';
SELECT * FROM SC WHERE Cno = '3';
注意,WHERE子句中是不能用聚集函数作为条件表达式的。
聚集函数只能用于SELECT子句和GROUP BY中的HAVING子句。
5. GROUP BY 字句
GROUP BY
子句将查询结果按某一列或多列的值分组,值相等的为一组。
对查询结果分组的目的是为了细化聚集函数的作用对象。
如果未对查询结果分组,聚集函数将作用于整个查询结果。分组后聚集函数将作用于每一个组,即每一组都有一个函数值。
例:求各个课程号及相应的选课人数
SELECT Cno,count(Sno) FROM sc GROUP BY Cno;
如果分组后还要求按一定的条件对这些组进行筛选,最终只输出满足指定条件的组,则可以使用HAVING短语指定筛选条件。
例:查询选修了3门及以上课程的学生学号。
SELECT Sno FROM sc GROUP BY Sno HAVING count(Cno)>=3;
WHERE子句与 HAVING短语的区别在于作用对象不同。WHERE子句作用于基本表或视图,从中选择满足条件的元组。HAVING短语作用于组,从中选择满足条件的组。
WHERE子句中是不能用聚集函数作为条件表达式的.
例:查询平均成绩大于等于90的学生学号和平均成绩
SELECT Sno, AVG(Grade) FROM sc GROUP BY Sno HAVING AVG(Grade)>=90;
3.4.2 连接查询
若一个查询同时涉及两个以上的表,则称之为连接查询。
连接查询是关系数据库中最主要的查询,包括:
- 等值连接查询
- 自然连接查询
- 非等值连接查询
- 自身连接查询
- 外连接查询
- 复合条件连接查询
- …
1. 等值与非等值连接查询
连接查询的WHERE子句中用来连接两个表的条件称为连接条件或连接谓词,其一般格式为
[<表名1>.]<列名1> <比较运算符> [<表名2>.]<列名2>
- 其中比较运算符主要有=、>、<、>=、<、!=(或<>)等。
此外连接谓词还可以使用下面形式:
[<表名1>.]<列名1> BETWEEN [<表名2>.]<列名2> AND [<表名2>.]<列名3>
当连接运算符为= 时,称为 等值连接。
使用其他运算符称为非等值连接。
连接谓词中的列名称为连接字段。连接条件中的各连接字段类型必须是可比的,但名字不必相同。
例:查询每个学生及其选修课程的情况
SELECT s.*, sc.* FROM student AS s, sc # 通过学号将两个表进行关联 WHERE s.Sno = sc.Sno;
若在等值连接中把目标列中重复的属性列去掉则为自然连接。
SELECT s.Sno, Sname, Ssex, Sage, Sdept, Cno, Grade FROM student AS s, sc WHERE s.Sno = sc.Sno;
由于Sname,Ssex,Sage,Sdept,Cno和 Grade属性列在Student表与SC表中是唯一的,因此引用时可以去掉表名前缀;而Sno在两个表都出现了,因此引用时必须加上表名前缀。
加上表名前缀查询的效率会更高,因为不用判断是哪个表的属性。
一条SOL语句可以同时完成选择和连接查询,这时WHERE子句是由连接谓词和选择谓词组成的复合条件。
例:查询选修2号课程且成绩在90分以上的所有学生的学号和姓名。
SELECT s.Sno, Sname FROM student AS s, sc # 先选出2号课程和90分以上的数据,再进行连接 # 查询效率更高 WHERE Cno = '2' AND Grade > 90 AND s.Sno = sc.Sno;
2. 自身连接
连接操作不仅可以在两个表之间进行,也可以是一个表与其自己进行连接,称为表的自身连接。
注意:
- 需要给表起别名以示区别
- 由于所有属性名都是同名属性,因此必须使用表的别名前缀
例:查询每一门课的间接先修课(即先修课的先修课)
SELECT c1.Con, c2.Cpno FROM mydb1.course c1, mydb1.course c2 # c1 的先修课为 c2 中的课程,c1 的间接先修课为 c2的先修课 WHERE c1.Cpno = c2.Con;
3. 外连接
在通常的连接操作中,只有满足连接条件的元组才能作为结果输出。
有时想以Student表为主体列出每个学生的基本情况及其选课情况。若某个学生没有选课,仍把Student的悬浮元组保存在结果关系中,而在SC表的属性上填空值NULL,这时就需要使用外连接。
SELECT s1.Sno, Sname, Ssex, Sage, Sdept, Cno, Grade FROM Student s1 LEFT OUTER JOIN SC s2 ON s1.Sno = s2.Sno;
左外连接列出左边关系(如本例 Student)中所有的元组,右外连接列出右边关系中所有的元组。
4. 多表连接
连接操作除了可以是两表连接、一个表与其自身连接外,还可以是两个以上的表进行连接,后者通常称为多表连接。
关系数据库管理系统在执行多表连接时,通常是先进行两个表的连接操作,再将其连接结果与第三个表进行连接。
例:查询每个学生的学号、姓名、选修的课程名及成绩。
SELECT s.Sno, Sname, Cname, Grade FROM Student s, SC, Course c # 先两张表,再第三张表 WHERE s.Sno = SC.Sno AND SC.Cno = c.Con;