第9讲:结果计算与聚集计算
select子句后不仅可接列名,还可接计算表达式或聚集函数,表明在投影的同时直接进行一些运算。
一、结果计算
1. 语法形式:select 列名 | expr | agfunc(列名) [[, 列名 | expr | agfunc(列名)] ... ] from 表名1 [, 表名2 ... ] [where 检索条件];
①expr:常量,列名,由常量、列名、特殊函数及算术运算符构成的算术运算式
②agfunc:聚集函数,如求平均、求和等
【示例1】求有差额(差额>0)的任意两位教师的薪水差额:
- select T1.Tname as TR1, T2.Tname as TR2, T1.Salary - T2.Salary from Teacher T1, Teacher T2 where T1.Salary > T2.Salary;
【示例2】依据学生年龄求学生的出生年份,当前是2019年:
- select S.S#, S.Sname, 2019 - S.Sage + 1 as Syear from Student S;
二、利用聚集函数进行统计计算
1. SQL提供了五个作用在简单列值集合上的内置聚集函数
聚集函数 | 功能描述 |
count | (关于某列)求个数 |
sum | (关于某列)求和 |
avg | (关于某列)求平均 |
max | (关于某列)求最大值 |
min | (关于某列)求最小值 |
【示例1】求教师工资的总额:
- select sum(Salary) from Teacher;
【示例2】求计算机系教师工资的总额:
- select sum(Salary) from Teacher T, Dept where T.D# = Dept.D# and Dept.Dname = '计算机';
【示例3】求数据库课程的平均成绩:
- select avg(Score) from SC, Course C where SC.C# = C.C# and C.Cname = '数据库';
- 思考:此例只求了一门课程的平均成绩,那么如何求每一个学生或每一门课程的平均成绩呢?
三、分组查询
1. 分组:SQL可以将检索到的元组按照某一条件进行分类,具有相同具有相同条件值的元组划到一个组或一个集合中,同时处理多个组或集合的聚集运算。
①基本语法形式:select 列名 | expr | agfunc(列名) [[, 列名 | expr | agfunc(列名)] ... ] from 表名1 [, 表名2 ... ] [where 检索条件] [group by 分组条件];
②分组条件:单个列名或者多个列名
【示例1】求每一个学生的平均成绩:
- select S#, avg(Score) from SC group by S#; // 按学号进行分组,于是学号相同的元组被划到同一个组中并求平均值
【示例2】求每一门课程的平均成绩:
- select C#, avg(Score) from SC group by C#; // 按课号进行分组,于是课号相同的元组被划到同一个组中并求平均值
【示例3】求不及格课程超过两门的同学的学号:
- select S# from SC where Score < 60 and count(*) > 2 group by S#;
- 思考:该句并不正确,主要原因是聚集函数count(*)不能出现在where子句中
- 因为where子句是对每一个元组进行条件过滤,而聚集函数则是对一个分组进行条件过滤,故聚集函数不应出现
四、分组过滤
1. 分组过滤的定义:对分组进行条件过滤,即满足条件的分组留下,不满足条件的分组过滤
2. having子句(分组过滤子句)
① 在分完组之后,用having子句来判断哪些分组保留,故需要有group by子句支持
②语法形式:select 列名 | expr | agfunc(列名) [[, 列名 | expr | agfunc(列名)] ... ] from 表名1 [, 表名2 ... ] [where 检索条件] [group by 分组条件 [having 分组过滤条件]];
③语义:把满足分组过滤条件的分组保留下来,把不满足分组过滤条件的分组过滤掉
【示例1】求不及格课程超过两门的同学的学号:
- select S# from SC where Score < 60 group by S# having count(*) > 2;
- "having count(*) > 2"检查每个分组中元组的个数是否大于2,并将元组个数大于2的分组保留下来
【示例2】求有10人以上不及格的课程号:
- select C# from SC where Score < 60 group by C# having count(*) > 10;
【示例3】having子句与where子句表达条件的区别:
- 对每一元组检查满足与否的条件要用where子句表达
- 对每一分组检查满足与否的条件要用having子句表达