本篇主要总结基于单表的查询,内容涉及去重查找,条件查询,模糊查询,分组查询等内容。测试结果一律采用先显示SQL语句,再显示测试结果(以图片的形式进行展现)的方式。
一、准备工作
本次的所有操作都将基于三张表,分别是学生表(Student),课程表(Course),学生选课表(SC)。具体建表语句这里不再赘述,直接给出表中数据内容。
1.学生表(Student)
2.课程表(Course)
3.学生选课表(SC)
二、单表查询——仅涉及一个表的查询
0.查询的一般格式为:
select (distinct) 目标列表达式
from 表名或视图名
where 条件表达式
group by 列名 having 条件表达式
order by ASC|DESC
1.选择表中的若干列
(1)查询指定列(这里回顾了上篇内容,其实上一篇已经写过)
例1:查询全体学生的学号和姓名。其中各个列的先后顺序可以自己根据需要决定,没有硬性规定。
select Sno,Sname
from Student;
例2:查询全体学生的姓名、学号、所在系。
select Sname,Sno,Sdept
from Student;
(2)查询全部列
方式一:列出所有的列名
select Sno,Sname,Ssex,Sage,Sdept
from Student;
方式二:使用通配符*
select *
from Student;
可以发现,二者结果是一样的,不过*的查询结果是和建表时的列名出现的顺序是一致的,而自己列出所有的列名时,可以自定义各个列的顺序。
(3)查询经过计算的值
select子句的目标表达式不仅可以是表中的属性列,也可以是表达式
例1:查询全体学生的姓名及其出生年份
Student表中实际存储的是学生的年龄,即Sage,要查询出生年份,可以使用计算,即用当前的年份-学生的年龄
select Sname,2021-Sage
from Student
容易发现,当前的出生年份的查询结果没有显示列名,但实际上我们可以给它指定一个列名,这里我为该列命名为Birth
select Sname,2021-Sage as Birth
from Student
目标列的表达式不仅可以是算术表达式,还可以是字符串常量、函数等
例2:查询全体学生的姓名、出生年份和所在的院系,要求用小写字母表示系名。
补充:起别名,由于直接写最终的结果会显示无列名,所以可以通过在查询内容后加一个空格或者使用as关键字,之后加所起的名字即可。
select Sname,'Year of Birth' as 'Year of Birth',2021-Sage as Birth,LOWER(Sdept)as Sdept
from Student;
可以发现,系名全都变成了小写
相应的,可以转换为小写,就可以转换成大写,这里在小写的基础上进行转换。转换后,可以发现所有的系名已经由小写全部转换为大写
select Sname,'Year of Birth' as 'Year of Birth',2021-Sage as Birth,UPPER(Sdept)as Sdept
from Student;
2.选择表中的若干元组
(1)消除取值重复的行
两个本来并不完全相同的元组在投影到指定的某些列上后,可能会变成相同的行,可以使用distinct关键字来消除它们。
例1:查询选修了课程的学生学号
select Sno
from SC;
上述查询结果中包含了许多重复的行,出现的原因是一个人可以选不止一门的课程,为了去掉重复的行,使用关键字distinct
select distinct Sno
from SC;
如果没有distinct,则默认是all,即查询所有,查询的结果和不加all,也不加distinct的结果是一样的。
(2)查询满足条件的元组——通过where子句实现
常用的查询条件如下
查询条件 | 谓词 |
比较 | =,>,<,>=,<=,!=,<>,!>,!<;NOT+上述比较运算符 |
确定范围 | BETWEEN AND , NOT BETWEEN AND |
确定集合 | IN,NOT IN |
字符匹配 | LIKE,NOT LIKE |
空值 | IS NULL,NOT IS NULL |
多重条件 | AND,OR,NOT |
①比较大小
例1:查询计算机科学系全体学生的名单
select Sname
from Student
where Sdept='CS';
例2:查询所有年龄在20岁以下的学生姓名及其年龄
select Sname,Sage
from Student
where Sage<20;
例3:查询考试成绩不及格的学生的学号(由于一个学生可能不止一科不及格,所以使用了distinct关键字来去重)
select distinct Sno
from SC
where Grade<60;
查询结果为空,说明没有不及格的学生
②确定范围
谓词BETWEEN···AND···和NOT BETWEEN ··· AND···可以用来查找属性在某个范围内的元组,其中BETWEEN后的是范围的下限,即低值,AND后的是范围的上限,即高值。
例1:查询年龄在20-23(包括20和23)之间的学生的姓名、系别和年龄
select Sname,Sdept,Sage
from Student
where Sage between 20 and 23;
例2:查询年龄不在20-23之间的学生姓名、系别和年龄
select Sname,Sdept,Sage
from Student
where Sage not between 20 and 23;
③确定集合
谓词IN可以用来查找属性值属于指定集合的元组。
例1:查询计算机科学系(CS),数学系(MA)和信息系(IS)学生的姓名和性别
select Sname,Ssex
from Student
where Sdept in('CS','MA','IS');
与IN相对的是NOT IN,即不在指定集合中的元组
④字符匹配(模糊查询)
使用关键字like(not like),后面是响应的匹配,可以使用通配符%或者_
%(百分号)代表任意长度(长度可以为0)的字符串
下横线代表任意单个字符,长度有限制,即有多少个下横线就代表最多可以匹配的字符数
例1:查询所有姓刘的学生的姓名、学号和性别
select Sname,Sno,Ssex
from Student
where Sname like '刘%';
例2:查询姓欧阳且全名为三个汉字的学生的姓名(由于之前建的表中没有,这里新添了三条有关欧阳的数据)
我的不知道为啥,不能正常显示,我需要打8个下横线才会正常显示,少于8个,一个都不显示,还没找到合适的解决办法,但是%可以正常使用
select Sname
from Student
where Sname like '欧阳________';
例3:查询名字中第二个字为“阳”的学生的姓名和学号(这个的下横线又可以正常使用了,好奇怪。。。。)
select Sname,Sno
from Student
where Sname like '_阳%';
例4:查询所有不姓刘的学生的姓名、学号和性别
select Sname,Sno,Ssex
from Student
where Sname not like '刘%';
如果要查询的字符串本身就含有通配符%或_,这时就要使用ESCAPE '<换码字符>'短语对通配符进行转义了
例5:查询DB_Design课程的课程号和学分(在Course表中插入该课程,用于测试)
escape ''表示“\”为换码字符,这样匹配后它会将下横线转义为普通的下横线字符。
select Cno,Ccredit
from Course
where Cname like 'DB\_Design' escape '\';
⑤涉及空值的查询
例1:某些学生选修课程后没有参加考试,所以有选课记录,但没有考试成绩,查询缺少成绩的学生的学号和相应的课程号(插入一条这样的数据)
==PS:==这里的is绝对不可以用=代替!!!
select Sno,Cno
from SC
where Grade is null;
⑥多重条件查询
逻辑运算符AND和OR可用来连接多个查询条件,AND的优先级高于OR,但可以用括号改变优先级
例1:查询计算机科学系年龄在20岁以下的学生姓名
select Sname
from Student
where Sdept='CS' and Sage<20;
IN谓词实际上是多个OR运算符的缩写,因此前边的IN运算符的测试的SQL语句可以更改为
select Sname,Ssex
from Student
where Sdept='CS' or Sdept='MA' or Sdept='IS';
3.ORDER BY子句
可以使用order by子句对查询结果按照一个或多个属性列的升序(ASC)或降序(DESC)排列,默认为升序
例1:查询选修了3号课程的学生的学号及其成绩,查询结果按分数的降序排列
select Sno,Grade
from SC
where Cno=3
order by Grade desc;
对于空值,排序时显示的次序由具体的系统实现决定,若为升序,则空值在最后,若为降序,则空值在最前边
例2:查询全体学生情况,查询结果按所在系的系号升序排列,同一系中的学生按年龄降序排列
select *
from Student
order by Sdept,Sage desc;
4.聚集函数
①count()统计元组个数
例1:查询学生总数
select count(*)
from Student;
例2:查询选修了课程的学生人数(去重之后的,因为一个学生可以选修多门课程,而这里主要是统计都有谁选课了)
select count(distinct Sno)
from SC;
②AVG()计算一列值的平均值
例:计算选修1号课程的学生的平均成绩
select avg(Grade)
from SC
where Cno=1;
③MAX()计算某一列的最大值
例::查询选修1号课程的学生最高分数
select max(Grade)
from SC
where Cno=1;
④SUM求某一列值的总和
例:查询学生201215121选修课程的总学分数
select sum(Ccredit)
from SC,Course
where Sno='201215121'and SC.Cno=Course.Cno
5.GROUP BY子句
该子句将查询结果按某一列或多列的值分组,值相等的为一组,分组后聚集函数将作用于每一个组,即每一个组都有一个函数值
例:求各个课程号及相应的选课人数
select Cno,count(Sno)
from SC
group by Cno;
该语句对查询结果按照Cno的值分组,所有具有相同Cno值的元组为一组,然后对每一组作用聚集函数count进行计算,以求得该组的学生人数。如果分组后还要求按一定的条件对这些组进行筛选,可以使用having短语指定筛选条件
例:查询选修了三门及以上课程的学生学号
select Sno
from SC
group by Sno
having count(*)>=3;
6.遇到的问题:
模糊查询中的下横线通配符无法正常使用,百度查了好久,还没有看到合适的解决办法,希望尽快找到解决办法。