3.4 数据查询
3.4.1 单表查询
1 选择表中的若干列
(3)查询经过计算的值
select子句的<目标列表达式>不仅可以是表中的属性列,也可以是表达式。
<目标表达式>是算数表达式
【例3.19】查询全体学生的姓名及其出生年份。
Student表中存储的是年龄Sage,所以出生年份是一个表达式:2020-Sage
select Sname,2020-Sage
from Student;
其结果显示了学生的出生年份,但显示无列名,因为没有指定它的列名。
<目标表达式>也可以是字符串常量、函数等。
【例3.20】查询全体学生的姓名、出生年份和所在院系,系名用小写字母表示。
select Sname,'Year of Birth:',2020-Sage,lower(Sdept)
from Student;
这里加入了一列字符串,便于看表。
可以看到,上面两个表中皆有<无列名>的列名,可以通过指定别名来改变查询结果的列标题,比如:
select Sname NAME,'Year of Birth:'BIRTH,2020-Sage BIRTHDAY,lower(Sdept)DEPARTMENT--小写
from Student;
这样就可以给每列取列名了。当然,这里的系名要求是小写,也可改为大写。
lower() | 小写 |
---|---|
upper() | 大写 |
select Sname NAME,'Year of Birth:'BIRTH,2020-Sage BIRTHDAY,upper(Sdept)DEPARTMENT--大写
from Student;
2 选择表中的若干元组
(1)消除取值重复的行
用distinct消除重复的行,缺省为all,即保留重复的行。
【例3.21】查询选修了课程的学生学号
select Sno from SC;
此时未指定distinct关键字,默认为all,结果包含重复行:
select distinct Sno from SC--消去重复行;
(2)查询满足条件的元组
通过where子句实现。其包含的常用的查询条件如如下表:
查询条件 | 谓词 |
---|---|
比较 | =,>,<,>=,<=,!=,<>,!>,!<;not+上述比较运算符 |
确定范围 | between and,not between and |
确定集合 | in,not in |
字符匹配 | like,not like |
空值 | is null,is not null |
多重条件(逻辑运算) | and,or,not |
a. 比较
【例3.22】查询计算机科学系全体学生的名单。
select Sname
from Student
where Sdept='CS';--计算机科学系
【例3.23】查询所有年龄在20岁以下的学生姓名及其年龄。
select Sname ,Sage
from Student
where Sage<20;--年龄小于20
【例3.24】查询考试不及格的学生的学号。
select distinct Sno
from SC
where Grade<60;
b. 确定范围
谓词between and 和not between and 查找属性值在指定范围内的元组,包含上界和下界。
【例3.25】查询年龄在18~20岁之间的学生的姓名、系别和年龄。
select Sname,Sdept,Sage
from Student
where Sage between 18and 20;
【例3.26】查询年龄不在18~20岁之间的学生姓名、系别和年龄。
select Sname,Sdept,Sage
from Student
where Sage not between 18and 20;
因为表里的年龄都在18~20岁之间,所以就不放截图了。
between and也可以用>=和<=代替。
c. 确定集合
in查找属性值属于指定集合的元组,not in 查找属性值不指定集合的元组
【例3.27】~【例3.28】用in查询CS、MA和IS系的学生的姓名和性别,not in查询不是CS、MA系的学生的姓名和性别。
select Sname,Ssex
from student
where Sdept in('CS','MA','IS');--CS、MA和IS系
select Sname,Ssex
from Student
where Sdept not in('CS','MA');--不是CS、MA系
d. 字符匹配
like进行字符串的匹配,一般语法格式:
[not] like '<匹配串>' [ESCAPE'<换码字符>']
<匹配串>可以是一个完整的字符串,也可以含有通配符%和_。
% | 代表任意长度(长度可以为0)的字符串 |
---|---|
_ | 代表任意单个字符 |
【例3.29】查询学号为201215121的学生的详细情况
select *
from Student
where Sno like '201215121';
like 后面没有通配符,可以用=取代like谓词,它也等价于:
select *
from Student
where Sno='202115121';
【例3.30】查询所有姓张的学生的姓名、学号和性别
select Sname,Sno,Ssex
from Student
where Sname like '张%';
通配符%跟在了张的后面,所以姓名一列里姓张的学生都会被选择出来。
【例3.31】查询姓“欧阳”且全名为三个汉字的学生的姓名。
select Sname
from Student
where Sname like '欧阳_';--姓欧阳,名只有一个字
若查询姓欧阳且全名为四个汉字的学生时三字的姓名也会被查询出来
select Sname
from Student
where Sname like '欧阳__';--姓欧阳,名有两个字
【注】数据库字符集为ASCII时一个汉字需要两个_,当字符集为GBK时只需要一个。
【例3.32】查询名字中第二个字为“阳”的学生的姓名和学号。
select Sname,Sno
from Student
where Sname like '_阳%';
【例3.33】查询所有不姓刘的学生的姓名、学号和性别
select *
from Student ;
select Sname ,Sno,Ssex
from Student
where Sname not like '刘%';
当查询的字符串本身就含有通配符,需要使用escape '<换码字符>'短语对通配符进行转义。
【例3.34】查询DB_Design课程的课程号和学分。
select Cno,Ccredit
from Course
where Cname like 'DB\_Design' escape'\';
【例3.35】查询以“DB_”开头,且倒数第三个字符为i的课程的详细情况。
select *
from Course
where Cname like 'DB\_%i__' escape'\';
只有第一个_前面有换码字符,所以只转义第一个。
e. 涉及空值的查询
空值必须是NULL,不能是’ ‘(空格)和’‘(空白)。
【例3.36】查询缺少考试成绩的学生的学号和相应的课程号。
select Sno,Cno
from SC
where Grade is NULL;
如果NULL改为空格的话
select Sno,Cno
from SC
where Grade is ' ';
或
select Sno,Cno
from SC
where Grade is '';
空格和空白都是不能代替空值的。
【例3.37】查询所有有成绩的学生学号和课程号。
select Sno ,Cno
from SC
where Grade is not NULL;
f. 多重条件查询
用and和or连接多个查询条件,and的优先级高于or,但可以用括号改变优先级。
【3.38】查询计算机科学系年龄 在20岁以下的学生姓名。
select Sname
from Student
where Sdept='CS'and Sage<20;
3 ORDER BY 子句
该子句对查询结果按照一个或多个属性列的升序或降序排列,默认为升序。
对于空值,排序时显示的次序由具体系统实现来决定。我的电脑按升序空值元组排在最前,降序排在最后。
【例3.39】查询选修了3号课程的学生的学号及成绩,查询结果按分数的降序排列。
select Sno,Grade
from SC
where Cno=3
order by Grade desc;
【例3.40】查询全体学生情况,查询结果按所在系的系号升序排列,同一系中的学生按年龄降序排列。
select *
from Student
order by Sdept,Sage desc;
4. 聚集函数
count(*) | 统计元组个数 |
---|---|
count([distinct\all]<列名>) | 统计一列中值的个数 |
sum([distinct\all]<列名>) | 统计一列值得综合(此列必须是整值型) |
avg([distinct\all]<列名>) | 计算一列值得平均值(此列必须是整值型) |
max([distinct\all]<列名>) | 求一列中的最大值 |
min([distinct\all]<列名>) | 求一列中的最小值 |
distinct是计算时取消指定列中的重复值,缺省为all。
聚集函数遇到空值时,除count(*)外,都跳过空值而只处理非空值。
【注】where子句不能用聚集函数作为条件表达式,只能用于select和group by中的having子句。
【例3.41】查询学生总人数。
select * from Student;
select count(*)
from Student;
【例3.42】查询选修了课程的学生人数。
select count(distinct Sno)
from SC;
因为有SC表中有学生选了多个课程,所以应去掉重复的学号。
【例3.43】计算选修1号课程的学生平均成绩。
select avg(Grade)
from SC
where Cno=1;
【例3.44】查询选修1号课程的学生最高分数。
select max(Grade)
from SC
where Cno=1;
【例3.45】查询学生201215121选修课程的总学分数。
select sum(Ccredit)
from SC,Course
where Sno='201215121'and SC.Cno=Course.Cno;
5. GROUP BY 子句
将查询结果按某一列或多列的值分组,值相等的为一组。
【例3.46】求各个课程号及相应的选课人数。
select Cno,count(Sno)Num
from SC
group by Cno;
先按课程分类,每个课程都是一类,再用count计算选了该号课程的学生的总数。就是先分组,分组后聚集函数作用于每一个组。
【例3.47】查询选修了两门以上课程的学生学号。
select Sno
from SC
group by Sno
having count(*)>2;
这里先对学生进行分类,再选择出选的课数大于2的学生学号。
【个人总结】这次的内容蛮多的,写的时间也挺长的,不过不算很难,就最后的几个例题仔细思考了一下。通过做完这些例题,对语句似乎更熟悉了些。可能有的表前后矛盾,是因为有的例题数据不够,临时新插入了数据和对之前的某个数据进行了修改。