目录
一、数据查询语句的基本格式
二、单表查询
查询表中的若干列
查询指定列
查询经过计算的值
选择表中的若干元组
去重
条件查询
order by 子句
聚集函数
group by 子句
三、连接查询
等值与非等值连接查询
外连接
多表连接
四、嵌套查询
带有in谓词的子查询
带有比较运算符的子查询
带有any(some)或all谓词的子查询
带有exists谓词的子查询
五、集合查询
六、基于派生表的查询
select 要查的内容
from 查找的对象
where 查找的条件
group by 按什么分组
having 使用到函数的条件
order by 按照什么条件排序
select 列名1,列名2[,列名3,...]
from 表名;
如果要查询表中的所有列并且不用列的显示顺序,那么可以用符号“*”来代替所有列名,如果想要改变显示顺序,那么就要将所有的表名按照你想要的顺序写出来。
如果想要显示自己指定的列名可以在要查询的列名的后面加一个空格,然后输入自己想要的列名即可。
如果想要查询出经过一定的处理的列值,那么只需要将列名换成表达式即可,表达式可以是算术表达式、函数和字符串常量等
例:查询全体学生的姓名、出生年份和所在院系,要求给出生年份起别名:birthday,用小写字母表示系名
select Sname,2022-Sage birthday,lower(Sdept)
from Student;
有时候我们查到的结果可能是重复的,如果我们想要消除这些行可以使用distinct来消除它们。
例:查询选修了课程的学生学号,并去除重复的行。
select distinct Sno
from Sc;
条件查询可以通过where子句实现,下面是where子句的常用查询条件。
查询条件 | 谓词 |
---|---|
比较 | =,>,<,>=,<=,!=,<>,!>,!<;NOT+上述比较运算符 |
确定范围 | between and,not between and |
确定集合 | in,not in |
字符匹配 | like,not like |
空值 | is null,is not null |
多重条件(逻辑运算) | and,or,not |
(1)比较大小
例:查询计算机科学系全体学生的名单
select Sname
from Student
where Sdept = 'CS';
(2)确定范围
例:查询年龄在20~23岁(包括20岁和23岁)之间的学生的姓名、系别和年龄
select Sname,Sdept,Sage
from Student
where Sage between 20 and 23;
(3)确定集合
例:查询计算机科学系(CS)、数学系(MA)、信息系(IS)学生的姓名和性别。
select Sname,Ssex
from Student
where Sdept in ('CS','MA','IS');
(4)字符匹配
在字符匹配中,%代表任意长度(可以为0)的字符串,下划线代表任意单个字符。如果要查询的字符串中含有%或者下划线则可以用 escape 定义换码字符。当匹配串中不含通配符时,可以用等于运算符代替like谓词,用不等于运算符代替not like谓词。
例:查询以"DB_"开头,且倒数第三个字符为i的课程的详细情况。
select *
from Course
where Cname like 'DB\_%i__' escape '\';
(5)涉及空值的查询
空值查询中的is和is not不能用等于或者不等于代替,等于或不等于的前提是有值,空值没有值。
例:查询所有有成绩的学生学号和课程号。
select Sno,Cno
from Sc
where Grade is not null
(6)多重条件查询
逻辑运算符and和or可以用来连接多个查询条件。and的优先级高于or,但用户也可以用括号改变优先级。
例:查询计算机科学系年龄在20岁以下的学生姓名。
select Sname
from Student
where Sdept = 'CS' and Sage > 20;
order by子句用来给查询结果排序,ASC为升序排列,DESC为降序排列,默认值为升序。空值的显示次序有具体系统实现来决定。
例:查询全体学生情况,查询结果按所在系的系号升序排列,同一系中的学生按年龄降序排列。
select *
from Student
order by Sdept ASC,Sage DESC
为了进一步方便用户,增强检索功能,下面是常用的一些聚合函数。
函数名 | 作用 |
---|---|
count(*) | 统计元组个数 |
count([distinct|all] <列名>) | 统计一列中值的个数 |
sum([distinct|all] <列名>) | 计算一列值的总和,列值必须是数值型 |
avg([distinct|all] <列名>) | 计算一列值的平均值,列值必须是数值型 |
max([distinct|all] <列名>) | 求一列值中的最大值 |
min([distinct|all] <列名>) | 求一列值中的最小值 |
注:1.distinct代表计算时去除重复值,all代表计算时不去除重复值,默认为all。
2.当聚集函数遇到空值时,除count(*)外,都跳过空值而只处理非空值。
3.聚集函数只能用于select子句和group by中的having子句。
例:查询选修了课程的学生人数
select count(distinct Sno)
from Sc;
group by子句将查询结果按某一列或多列的值分组,值相等的为一组。如果未对查询结果分组,聚集函数将作用于整个查询结果,分组后聚集函数将作用于每一组,即每一组都有一个函数值。
例:查询选修了三门以上课程的学生学号。
select Sno
from Sc
group by Sno
having count(*) > 3;
通常情况下,只查询一个表并不能满足我们的需求,这时就引入了连接查询。如果一个查询同时涉及两个以上的表,则称之为连接查询。
连接查询的where子句中用来连接两个表的条件称为连接条件或连接谓词,其一般格式为
[<表名1>.]<列名1><比较运算符>[<表名2>.]<列名2>
[<表名1>.]<列名1> between [<表名2>.]<列名2> and [<表名2>.]<列名3>
当比较运算符为“=”时,称为等值连接,其余则为非等值连接。连接条件中的列名称为连接字段,各连接字段的名称不必相同,但必须是可比的。在等值连接中,去掉目标列中的重复列称为自然连接
例:查询选修2号课程且成绩在90分以上的所有学生的学号和姓名。
select Student.Sno,Sname
from Student,Sc
where Student.Sno = Sc.Sno and Sc.Cno = '2' and Sc.Grade > 90;
自身连接
一个表自己与自己连接叫做自身连接。
例:查询每一门课的间接先修课(即先修课的先修课)。
select first.Cno,second.Cpno
from Course first,Course second
where first.Cpno = second.Cno;
普通连接操作只输出满足连接条件的元组,外连接操作以指定表为主体,将主体表中不满足连接条件的元组一并输出。外连接分为左外连接和右外连接,如果列出左表中的所有元组,则称为左外连接;列出右表的所有元组,则成为右外连接。
例:查询每个学生及其选修课程的情况,未选课的学生的选课情况以空值输出。
select Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade
from Student left outer join Sc on (Student.Sno = Sc.Sno);
或
select Student.*,Sc.*
from Student left outer join Sc using(Sno);
两个表以上的连接称为多表连接
例:查询每个学生的学号、姓名、选修的课程名及成绩。
select Student.Sno,Sname,Cname,Grade
from Student,Sc,Course
where Student.Sno = Sc.Sno and Sc.Cno = Course.Cno;
在SQL语言中,一个select-from-where语句称为一个查询块。将一个查询块嵌套在另外一个查询块中的where子句或having短语的条件中的查询称为嵌套查询。被嵌套的查询块称为内层查询或子查询,另一个则为外层查询或父查询。需要注意的是,group by子句只能对最终的查询结果进行排序,也就是只能用在最外层的查询中,不能用在任何子查询中。
如果子查询的条件不依赖于父查询,则称为不相关子查询。如果子查询的条件依赖于父查询,则称为相关子查询。
例:查询选修了课程名为“信息系统”的学生的学号和姓名。
select Sno,Sname
from Student
where Sno in
(select Sno
from Sc
where Cno in
(select Cno
from Course
where Cname = '信息系统'
)
);
父查询与子查询之间用比较运算符进行连接,这时内层查询返回的是单个值。
例:找出每个学生超过他自己选修课程平均成绩的课程号。
select Sno,Cno
from Sc x
where Grade >= (
select avg(Grade)
from Sc y
where x.Sno = y.Sno);
子查询返回多个值时要用any或all谓词修饰符,并且必须同时使用比较运算符。谓词any的意思是结果中的某个值,all的意思是结果中的所有值。
例:查询非计算机科学系中比计算机科学系所有学生年龄都小的学生姓名及年龄。
select Sname,Sage
from Student
where Sage < all
(select Sage
from Student
where Sdept = 'CS')
and Sdept <> 'CS';
此类子查询不返回任何数据,只产生逻辑真值“true”或逻辑假值“false”。由exists引出的子查询,其目标表达式通常用*,因为带exists的子查询只返回真值或假值,给出列名无实际意义。
例:查询选修了全部课程的学生姓名。
select Sname
from Student
where not exists
(
select *
from Course
where not exists
(
select *
from Sc
where Sno = Student.Sno and Cno = Course.Cno
)
);
查询的结果是一个个元组的集合,所以多个查询结果之间可以进行集合操作。集合操作主要包括交(intersect)、并(union)和差(except)。需要注意的是,参加集合操作的各查询结果的列数和对应项的数据类型必须相同。
例:查询计算机科学系的学生及年龄不大于19岁的学生。
select *
from Student
where Sdept = 'CS'
union
select *
from Student
where Sage <= 19;
注意:并操作会自动去除相同的元组,如果不想去除重复的元组可以用union all操作符。
除去返回逻辑真假值的情况,子查询返回的结果可以认为是一个表,那么子查询的结果就可以作为一个临时派生表出现在from子句中,成为主查询的查询对象。
例:找出每个学生超过他自己选修课程平均成绩的课程号。
select Sno,Cno
from Sc,(select Sno,Avg(Grade) from Sc group by Sno)
as Avg_sc(avg_sno,avg_grade) -- 给派生表指定表名和属性列名
where Sc.Sno = Avg_sc.avg_sno and Sc.Grade >= Avg_sc.avg_grade;
注意:1.如果子查询中没有聚集函数,那么可以不给派生表指定属性列名。
2.通过from子句生成派生表时,as关键字可以省略,但必须为派生关系起一个别名。