一、学生-课程数据库数据示例
(一)学生表
学号(Sno) |
姓名(Sname) |
性别(Ssex) |
年龄(Sage) |
所在系(Sdept) |
200215121 |
李勇 |
男 |
20 |
CS |
200215122 |
刘晨 |
女 |
19 |
CS |
200215123 |
王敏 |
女 |
18 |
MA |
200215125 |
张立 |
男 |
19 |
IS |
(二)课程表
课程号(Cno) |
课程名(Cname) |
先行课(Cpno) |
学分(Ccredit) |
1 |
数据库 |
5 |
4 |
2 |
数学 |
|
2 |
3 |
信息系统 |
1 |
4 |
4 |
操作系统 |
6 |
3 |
5 |
数据结构 |
7 |
4 |
6 |
数据处理 |
|
2 |
7 |
PASCAL语言 |
6 |
4 |
(三)选课表
学号(Sno) |
课程号(Cno) |
成绩(Grade) |
200215121 |
1 |
92 |
200215121 |
2 |
85 |
200215121 |
3 |
88 |
200215122 |
2 |
90 |
200215122 |
3 |
80 |
二、查询
(一)单表查询
1、选择表中的若干列(对列操作)
(1)查询指定列
(2)查询全部列
(3)查询经过计算的值
【例1】查询全体学生的姓名、出生年份和所在的院系,要求用小写字符表示所有系名。
SQL语句:SELECT Sname,'Year of Birth',2004-Sage,LOWER(Sdept) FROM student;
查询结果:
2、选择表中的若干元组(对行操作)
(1)消除取值重复的行
两个本来并不完全相同的元组,投影到指定的某些列以后,可能变成相同的行了,可以使用DISTINCT取消重复的元组。格式如下:select distinct Sno form SC;
【例2】查询选修了课程的学生学号,要求不重复出现。
SQL语句:SELECT DISTINCT Sno FROM sc;
查询结果:
(2)查询满足条件的元组(where条件查询)
查询条件 |
谓词 |
|
比较 |
=, >, <, >=, <=, !=, <>, !>, !<, NOT+上述比较运算符 |
|
确定范围 |
between and(a<=x<=b),not between and |
|
确定集合 |
in,not in |
|
字符匹配 |
like,not like |
|
%:任意长度(可为0)字符串 |
_:任意单个字符 |
|
注意:字符集为ASCII时,一个汉字需要两个‘_’; 字符集为GBK时,一个汉字需要一个‘_’ |
||
如果用户要查询的字符串本身含有通配符,使用转义字符’\’ |
||
空值 |
is NULL,is not NULL(判空不能用=) |
|
多重条件(逻辑运算) |
and,or,not |
【例3】查询年龄不在20-23岁之间的学生姓名、系别和年龄。
SQL语句:SELECT Sname,Sdept,Sage FROM student WHERE Sage NOT BETWEEN 20 AND 23;
查询结果:
【例4】查询计算机科学系(CS)、数学系(MA)学生的姓名和性别。
SQL语句:SELECT Sname,Ssex FROM student WHERE Sdept IN ('CS','MA');
查询结果:
【例5】查询所有姓刘的学生的全部信息。
SQL语句:SELECT * FROM student where Sname LIKE '刘%';
查询结果:
【例6】查询所有以“数据”开头且课程名为四个字的课程全部信息。
SQL语句:SELECT * FROM course where Cname LIKE '数据__';
查询结果:
【例7】查询没有先修课程的课程全部信息。
SQL语句:SELECT * FROM course where Cpno IS NULL;
查询结果:
3、ORDER BY子句
用户可以使用ORDER BY子句对查询结果按照一个或多个属性列的升序(ASC)或者降序(DESC)排列,缺省值为升序。
如果是按照多个属性列进行排序,则首先按照第一个属性排序,当第一个属性相同时,再按照第二个属性列排序,以此类推。
ORDER BY子句放在WHERE条件的后面。例如:select *from Student where Ssex=’男’ order by Sno,Sage desc;
【例8】查询选修了3号课程的所有信息,查询结果按照分数的降序排列。
SQL语句:SELECT * FROM sc WHERE Cno=3 ORDER BY Grade DESC;
查询结果:
4、聚集函数
在聚集函数中遇到空值时,除了COUNT(*) 外,都跳过空值而只处理非空值。注意,WHERE子句中不能使用聚集函数作为条件表达式的。如果指定DISTINCT短语,则表示在计算时要取消指定列中的重复值。
聚集函数 |
含义 |
COUNT([DISTINCT|ALL]*) |
统计元组个数 |
COUNT([DISTINCT|ALL]<列名>) |
统计一列中值的个数 |
SUM([DISTINCT|ALL]<列名>) |
计算一列值的总和(必须是整型) |
AVG([DISTINCT|ALL]<列名>) |
计算一列值的平均值(必须是整型) |
MAX([DISTINCT|ALL]<列名>) |
求一列值中的最大值 |
MIN([DISTINCT|ALL]<列名>) |
求一列值中的最小值 |
【例9】计算1号课程的学生平均成绩。
SQL语句:SELECT AVG(Grade) average FROM sc WHERE Cno=1;
查询结果:
5、GROUP BY 子句
GROUP BY 子句将查询结果按某一列或多列的值分组,值相等的为一组。
对查询结果分组的目的是为了细化聚集函数的作用对象。如果未对查询结果分组,聚集函数将作用于整个查询结果,分组后聚集函数将作用于每个组,即每一组都有一个函数值。
如果分组后还要求按一定的条件对这些组进行筛选,最终只输出满足指定条件的组,则可以使用HAVING短语指定筛选条件。例如:SELECT * FROM sc GROUP BY Sno HAVING Count(*)>=2;(查询选修了2门及以上课程的学生学号)。
WHERE子句和HAVING短语的区别在于作用对象不同。WHERE子句作用于基本表或视图,从中选择满足条件的元组。HAVING短语作用于元组,从中选择满足条件的元组。
【例10】查询各个课程号及相应的选课人数。
SQL语句:SELECT Cno,COUNT(Sno) num FROM sc GROUP BY Cno;
查询结果:
【例11】查询选修了2门及以上课程的学生学号。
SQL语句:SELECT Sno FROM sc GROUP BY Cno HAVING COUNT(*)>=2;
查询结果:
(二)连接查询
1、等值与非等值连接
WHERE子句中用来连接两个表的条件称为连接条件或连接谓词,其一般格式为:[<表名1>.]<列名1> <比较运算符> [<表名2>.]<列名2>。此外,连接谓词还可以使用下面形式:[<表名1>.]<列名1> BETWEEN [<表名2>.]<列名2> AND [<表名2>.]<列名3>。
当连接运算符为“=”时,称为等值连接,使用其他运算符称为非等值连接。
如果属性名在参加连接的各表中是唯一的,则可以省略表名前缀。
若在等值连接中把目标列中重复的属性列去掉则为自然连接。
【例12】查询每个学生及其选课情况。
SQL语句:SELECT student.*,sc.* FROM student,sc WHERE student.Sno = sc.Sno;
查询结果:
2、自身连接
连接操作不仅可以在两个表之间进行,也可以是一个表与其自己进行连接,称为表的自身连接。例如:SELECT FIRST.Cno,SECOND.Cpno FROM Course FIRST,COURSE SECOND WHERE FIRST.Cpno=SECOND.Cpno;(查询每一门课的间接先修课,即先修课的先修课)
【例13】查询每一门课的间接先修课(即先修课的先修课)。
SQL语句:SELECT FIRST.Cno,SECOND.Cpno from course FIRST,course SECOND WHERE `FIRST`.Cno = `SECOND`.Cno;
查询结果:
3、外连接
外连接是以一个表为主体列列出需要查询的元组信息,如果别的表中的列没有相应的属性值则为空值。左外连接列出左边关系中所有元组,右外连接列出右边关系中所有的元组。例如表A LEFT OUTER JOIN 表B,则代表以表A为主体列;表A RIGHT OUTER JOIN 表B,则代表以表B为主体列。
【例14】以Student表为主体,查询每个学生的基本情况及选课情况。
SQL语句:SELECT student.Sno,Sname,Sage,Ssex,Sdept,Cno,Grade FROM student LEFT OUTER JOIN sc ON (student.Sno = sc.Sno);
查询结果:
4、复合条件连接
WHERE子句中可以有多个连接条件,称为复合条件连接。连接操作除了可以是两表连接,一个表与其自身连接外,还可以是两个以上的表进行连接,后者通常称为多表连接。
【例15】查询每个学生的学号、姓名、选修的课程名及成绩。
SQL语句:SELECT student.Sno,Sname,Cname,Grade FROM student,course,sc WHERE student.Sno=sc.Sno AND sc.Cno=course.Cno;
查询结果:
(三)嵌套查询
子查询的SELECT语句中不能使用ORDER BY子句,ORDER BY子句只能对最终查询结果排序。
1、带有IN谓词的子查询
在嵌套查询中,子查询的结果往往是一个集合,所以谓词IN是嵌套查询中最常用的谓词。例如:查询与“刘晨”在同一个系学习的学生全部信息。SELECT * FROM Student WHERE Sdept IN(SELECT Sdept FROM Student WHERE Sname=’刘晨’);
【例16】查询与“刘晨”在同一个系的学生。
SQL语句:SELECT Sno,Sname,Sdept FROM student WHERE Sdept IN (SELECT Sdept FROM student where Sname='刘晨');
查询结果:
2、带有比较运算符的子查询
带有比较运算符的子查询是指父查询与子查询之间用比较运算符进行连接。当用户能确切知道内层查询返回的是单值时,可以用比较运算符。需要注意的是,在Oracle中子查询一定要跟在比较运算符后面。
例如找出每个学生超过他选修课程平均成绩的课程号:SELECT Sno,Cno FROM SC x WHERE Grade >= (SELECT AVG(Grade) FROM SC y WHERE x.Sno=y.Sno);
【例17】找出每个学生超过他选修课程平均成绩的课程号。
SQL语句:SELECT Sno,Cno FROM sc x WHERE Grade > (SELECT AVG(Grade) FROM sc y WHERE y.Sno = x.Sno);
查询结果:
3、带有ANY(SOME)或ALL谓词的子查询
子查询返回单指时可以用比较运算符,但返回多值时要用ANY(有的系统用)或ALL谓词修饰符。而使用ANY或ALL谓词时则必须同时使用比较运算符。其中,ANY的意思是查询结果中的某个值,ALL的意思是查询结果中的所有值。
例如:查询其他系中比计算机科学系某一学生年龄小的学生的所有信息记录。SELECT * FROM Student WHERE Sage < ANY(SELECT Sage FROM Student WHERE Sdept != ‘CS’);
【例18】查询其他系中比计算机科学系某一学生年龄小的学生的所有信息记录。
SQL语句:SELECT * FROM Student WHERE Sage < ANY(SELECT Sage FROM Student WHERE Sdept != ‘CS’);
查询结果:
4、带有EXISTS谓词的子查询
EXISTS代表存在量词。带有EXISTS谓词的子查询不返回任何数据,只产生逻辑真值true或逻辑假值false。使用存在量词EXISTS后,若内层查询结果非空,则外层的WHERE子句返回真值,否则返回假值。
由EXISTS引出的子查询,其目标列表达式通常用*,因为带EXISTS的子查询只返回真假值,给出列名无实际意义。
与EXISTS谓词对应的是NOT EXISTS谓词。使用存在量词NOT EXISTS后,若内层查询结果为空,则外层的WHERE子句返回真值,否则返回假值。
一些带EXISTS或NOT EXISTS谓词的子查询不能被其他形式的子查询等价替换,但所有带IN谓词、比较运算符、ANY和ALL谓词的子查询都能用带EXISTS谓词的子查询等价替换。
【例19】查询没有选修1号课程的学生姓名。
SQL语句:SELECT Sname FROM student WHERE NOT EXISTS (SELECT * FROM sc WHERE Sno=student.Sno AND Cno=1);
查询结果:
【例20】查询至少选修了学生200215122选修的全部课程的学生号码(P111)。
SQL语句:SELECT DISTINCT Sno FROM sc scx WHERE NOT EXISTS (SELECT * FROM sc scy WHERE scy.Sno='200215122' AND NOT EXISTS (SELECT * FROM sc scz WHERE scz.Sno=scx.Sno AND scz.Cno=scy.Cno));
查询结果:
(四)集合查询
集合查询操作主要包括并操作INION、交操作INTERSECT和差操作EXCEPT。注意,参加集合操作的各查询结果的列数必须相同,对应项的数据类型也必须相同。
【例21】查询计算机科学系的学生及年龄不大于19岁的学生。
SQL语句:SELECT * FROM student WHERE Sdept='CS' UNION SELECT * FROM student WHERE Sage<=19;
查询结果: