虽然写这个博客主要目的是为了给我自己做一个思路记忆录,但是如果你恰好点了进来,那么先对你说一声欢迎。我并不是什么大触,只是一个菜菜的学生,如果您发现了什么错误或者您对于某些地方有更好的意见,非常欢迎您的斧正!
本章基础知识脑图:
https://pan.baidu.com/s/1urSwbPkCYSWksVUKjbR-QQ
贯穿这一章的三张表:(真是令人头大!)
Student
学号 Sno |
姓名 Sname |
性别 Ssex |
年龄 Sage |
所在系 Sdept |
201215121 |
李勇 |
男 |
20 |
CS |
201215122 |
刘晨 |
女 |
19 |
CS |
201215123 |
王敏 |
女 |
18 |
MA |
201215125 |
张立 |
男 |
20 |
IS |
Course
课程号 Cno |
课程名 Cname |
先行课 Cpno |
学分 Ccredit |
1 |
数据库 |
5 |
4 |
2 |
数学 |
|
2 |
3 |
信息系统 |
1 |
4 |
4 |
操作系统 |
6 |
3 |
5 |
数据结构 |
7 |
4 |
6 |
数据处理 |
|
2 |
7 |
PASCAL语言 |
6 |
4 |
SC
学号 Sno |
课程号 Cno |
成绩 Grade |
201215121 |
1 |
92 |
201215121 |
2 |
85 |
201215121 |
3 |
88 |
201215122 |
2 |
90 |
201215122 |
3 |
80 |
例3.16:查询全体学生的学号和姓名
SELECT Sno,Sname
FROM Student;
例3.17:查询全体学生的姓名、学号、所在系(为了说明各个列的先后顺序可以与表中不一样)
SELECT Sname,Sno,Sdept
FROM Student;
例3.18:查询全体学生的详细记录(为了说明*的用法)
SELECT *
FROM Student;
等价于:
SELECT Sno,Sname,Ssex,Sage,Sdept
FROM Student;
例3.19:查询全体学生的姓名及其出生年份(查询经过计算的值:出生年份要经过计算才能知道)
SELECT Sname,2018-Sage/*出生年份=2018-岁数*/
FROM Student;
结果:
例3.20:查询全体学生的姓名,出生年份和所在系,要求用小写字母表示系名
SELECT Sname,'Year of Birth:',2018-Sage,LOWER(Sdept)
FROM Student;
输出结果:
用户可以指定别名来改变查询结果的标题:
SELECT Sname,'Year of Birth:' BIRTH,2018-Sage BIRTHDAY,LOWER(Sdept)
FROM Student;
输出结果:
例3.21:查询选修了课程的学生学号(主要讲解DISTINCT,消除相同的行的用法)
没有DISTINCT
SELECT Sno
FROM SC;
输出结果:
有了DISTINCT
SELECT DISTINCT Sno
FROM SC;
输出结果:
例3.23:查询所有年龄在20岁以下的学生姓名及年龄(开始涉及到查询条件)
SELECT Sname,Sage
FROM student
WHERE Sage<20;
例3.24:查询考试成绩不及格的学生的学号
SELECT DISTINCT Sno
FROM sc
WHERE Grade<60;
例3.25:查询年龄在20~23岁之间(包括20,23)的学生的姓名、系别和年龄。(注意BETWEEN AND,不在的话就使用NOT BETWEEN AND)
SELECT Sname,Sdept,Sage
FROM student
WHERE Sage BETWEEN 20 AND 23;
例3.27:查询系CS、MA、IS的学生的姓名和性别(谓词IN的使用,不在就用NOT IN)
SELECT Sname,Ssex
FROM student
WHERE Sdept IN('CS','MA','IS');/*WHERE Sdept='CS' OR Sdept='MA' OR Sdept='IS';*/
例3.29:查询学号为201215121的学生的详细情况(开始涉及到字符匹配)
SELECT *
FROM student
WHERE Sno LIKE '201215121';/*等于WHERE Sno='201215121'*/
例3.30:查询所有性刘的学生的姓名、学号和性别(%的使用)
SELECT Sname,Sno,Ssex
FROM student
WHERE Sname LIKE '刘%';
例3.31:查询姓“欧阳”且全名为3个汉字的学生的姓名(_的使用,数据库字符集为ASCII时一个汉字需要两个_,当字符集为GBK时只需要一个)
SELECT Sname
FROM student
WHERE Sname LIKE '欧阳_';
例3.32:查询名字中第二个字为“阳”的学生的姓名和学号
SELECT Sname
FROM student
WHERE Sname LIKE '_阳%';
例3.34:查询DB_Design课程的课程号和学分(ESCAPE'\'表示'\'为换码字符。这样匹配串中紧跟在'\'后面的字符'_'不再具有通配符的定义,转义为普通的“_”字符)
SELECT Cno,Ccredit
FROM course
WHERE Cname LIKE 'DB\_Design' ESCAPE '\';
例3.35:查询以“DB_”开头,倒数第三个字符为i的课程的详细情况。(一句废话:前面的是昨晚弄的,明明保存了草稿,还是差点找不到这个,心态差点崩。嘤嘤嘤)
SELECT *
FROM course
WHERE Cname LIKE 'DB\_%i__' ESCAPE '\';
例3.36:某些学生选修课程后没有参加考试,所以有选课记录,但是没有考试成绩,查询缺少成绩的学生的学号和相应的课程号。(涉及空值的查询)
SELECT Sno,Cno
FROM sc
WHERE Grade is NULL;/*如果是非空就用NOT NULL*/
例3.38:查询计算机科学系年龄在20岁以下的学生姓名。(多重条件的查询)
SELECT Sname
FROM student
WHERE Sdept='CS' AND Sage<20;
例3.39:查询选修了3号课程的学生的学号及其成绩,查询结果按分数的降序排列。(这边考察了ORDER BY子句:升序(ASC),降序(DESC))
SELECT Sno,Grade
FROM sc
WHERE Cno='3'
ORDER BY Grade DESC;
例3.40:查询全体学生情况,查询结果按所在系的系号升序排列,同一系中的学生按年龄降序排列。
SELECT *
FROM student
ORDER BY Sdept,Sage DESC;
例3.41:查询学生总人数(聚集函数COUNT的使用)
SELECT COUNT(*)
FROM student;
例3.42:查询选修了课程的学生人数(因为一个学生可能选修多门课,所以要使用DISTINCT)
SELECT COUNT(DISTINCT Sno)
FROM student;
例3.43:计算选修1号课程的学生平均成绩(聚集函数AVG)
SELECT AVG(Grade)
FROM sc
WHERE Cno='1';
例3.44:查询1号课程学生的最高分(聚集函数MAX)
SELECT MAX(Grade)
FROM sc
WHERE Cno='1';
例3.45:查询学生201215012选修课程的总学分数(聚集函数SUM)
SELECT SUM(Ccredit)
FROM sc,course
WHERE Sno='201215012' AND sc.Cno=course.Cno;
例3.46:求各个课程号及其相应的选课人数(GROUP BY子句:分组后聚集函数将作用于每个组,即每个组有一个函数值)
SELECT Cno,COUNT(Sno)
FROM sc
GROUP BY Cno;/*所有具有相同Cno的人为一组*/
例3.47:查询选修了三门以上课程的学生学号
SELECT Sno
FROM sc
GROUP BY Sno/*先用GROUP BY子句按Sno进行分组*/
HAVING COUNT(*)>3;/*再用聚集函数COUNT对每一组进行计数,HAVING短语给出了选择组的条件*/
/*WHERE子句中是不能用聚集函数作为条件表达式的*/
感觉已经忘记的差不多了,因为接下来的题大多涉及的不止一张表,就再放一次。
例3.49:查询每个学生及其选修课的情况(连接查询。显然Student与SC表都要涉及,它们的联系是Sno。)
SELECT student.*,sc.*/*注意表名后面的那个. */
FROM student,sc
WHERE student.Sno=sc.Sno;
这是一种等值连接。我们在例3.50中就会看到自然连接。
例3.50:对例3.49用自然连接完成(也就是Sno只出现一次)
SELECT student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade
FROM student,sc
WHERE student.Sno=sc.Sno;
可以看到此时Sno只输出一列
例3.51:查询选修2号课程(在SC表)且成绩在90分以上(在SC表)的所有学生的学号和姓名(在Student表)(WHERE子句是由连接谓词和选择谓词组成的复合条件)
SELECT student.Sno,Sname
FROM student,sc
WHERE student.Sno=sc.Sno AND sc.Cno='2' AND sc.Grade>90;
例3.52:查询一门课的间接选修课(自身连接)(我们看Course表,可以看到比如课程号5的先行课是7,课程号7的先行课又是6,那么课程号5的间接选修课就是6)
SELECT FIRST.Cno,SECOND.Cno
FROM course FIRST,course SECOND
WHERE FIRST.Cpno=SECOND.Cno;
例3.53:左外连接(想以Student表列出每个学生的基本情况和选课情况,但是某些学生没有选课,仍把Student的悬浮元组保存在结果中)
SELECT student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade
FROM student LEFT OUTER JOIN sc ON (student.Sno=sc.Sno);
输出结果:可以看到最后两行虽然没有选课,但是还是放进来了
例3.54:查询每个学生的学号、姓名(Student 表)、选课的课程名(Course表)及成绩(SC表)(多表连接)
SELECT student.Sno,Sname,Cname,Grade
FROM student,sc,course
WHERE student.Sno=sc.Sno AND sc.Cno=course.Cno;/*连接三个表*/
例3.55:查询与“刘晨”在同一个系学习的学生(嵌套查询 不相关子查询)
SELECT Sno,Sname,Sdept
FROM student
WHERE
Sdept IN (
SELECT Sdept
FROM student
WHERE Sname = '刘晨'
);
解法二:
SELECT S1.Sno,S1.Sname,S1.Sdept
FROM student S1,student S2
WHERE S1.Sdept=S2.Sdept AND S2.Sname='刘晨';
例3.56:查询选修了课程名为“信息系统”(Course表)的学生学号和姓名(Student表)(这两个表通过SC联系在一起)
SELECT Sno,Sname/*③最后根据学号获取信息*/
FROM student
WHERE Sno IN (/*②然后在SC表找出选修该课程号的学生的学号*/
SELECT Sno
FROM sc
WHERE Cno IN (/*①首先在Course中找出“信息系统”的课程号*/
SELECT Cno
FROM course
WHERE Cname = '刘晨'
)
);
例3.57:找出每个学生超过他自己选修课程平均成绩的课程号(带有比较运算符的子查询)(相关子查询)
SELECT Sno,Cno
FROM sc x/*别名*/
WHERE Grade>=( SELECT AVG(Grade)
ROM sc y
WHERE y.Sno=x.Sno);
例3.58:查询非计算机科学系(CS)中比计算机科学系任意一个学生年龄小的学生姓名和年龄(带有ANY(SOME)或ALL谓词的子查询)
SELECT Sname,Sage
FROM student
WHERE Sage'CS';
例3.60:查询所有选修了1号课程(SC表)的学生姓名(Student表)(带有EXISTS谓词的子查询,还有NOT EXISTS)
SELECT Sname
FROM student
WHERE EXISTS
(SELECT*
FROM sc
WHERE Sno=student.Sno AND Cno='1');
例3.62:查询选修了全部课程的学生的姓名(也就说没有一门课程是他不选修的!)
SELECT Sname
FROM student
WHERE NOT EXISTS (
SELECT *
FROM course
WHERE NOT EXISTS (
SELECT *
FROM sc
WHERE Sno = student.Sno
AND Cno = course.Cno
)
);
例3.63:查询至少选修了学生201215122选修的全部课程的学生号码(也就是说,不存在这样的课程y,学生201215122选修了y,而学生x没有选)
SELECT DISTINCT Sno
FROM sc SCX
WHERE NOT EXISTS
(SELECT *
FROM sc SCY
WHERE SCY.Sno='201215122' AND
NOT EXISTS
(
SELECT *
FROM sc SCZ
WHERE SCZ.Sno=SCX.Sno AND
SCZ.Cno=SCY.Cno));
例3.64:查询计算机科学系学生及年龄不大于19岁的学生(并操作UNION)
SELECT *
FROM student
WHERE Sdept='CS'
UNION
SELECT *
FROM student
WHERE Sage<=19;
/*或者*/
SELECT *
FROM student
WHERE Sdept='CS' OR Sage<=19;
例3.66:查询计算机科学系的学生与年龄不大于19岁的学生的交集(交操作INTERSECT)
SELECT *
FROM student
WHERE Sdept='CS'
INTERSECT
SELECT *
FROM student
WHERE Sage<=19;
/*或者*/
SELECT *
FROM student
WHERE Sdept='CS' AND Sage<=19;
例3.68:查询计算机科学系的学生与年龄不大于19岁的学生的差集(差操作EXCEPT)
SELECT *
FROM student
WHERE Sdept='CS'
EXCEPT
SELECT *
FROM student
WHERE Sage<=19;
/*或者*/
SELECT *
FROM student
WHERE Sdept='CS' AND Sage>19;
例3.60的基于派生表的查询:查询所有选修了1号课程(SC表)的学生姓名(Student表)(使用FROM子句查询)
SELECT Sname
FROM student,(SELECT Sno FROM sc WHERE Cno='1')AS SC1/*一定要写别名*/
WHERE student.Sno=SC1.Sno;
再放一次图
例3.69:将一个新学生元组(学号:201215128,陈冬,男,所在系:IS,18岁)插入到Student中(插入元组)
INSERT
INTO student(Sno,Sname,Ssex,Sdept,Sage)
VALUES('201215128','陈冬','男','IS',18);
例3.70:将学生张成民的信息插入到Student表中(没有认为安排的时候,注意一一对应)
INSERT
INTO student
VALUES('201215126','张成民','男',18,'CS');
例3.71:插入一条选课记录(‘201215128’,‘1’)(自动赋空值)
INSERT
INTO sc(Sno,Cno)
VALUES('201215128','1');
/*等同于*/
INSERT
INTO sc
VALUES('201215128','1',NULL);
例3.72:对于每一个系,求学生的平均年龄,并把结果存入数据库(插入子查询结果)
先建立一个新表
CREATE TABLE Dept_age
(Sdept CHAR(15)
Avg_age SMALLINT);
/*再分组*/
INSERT
INTO Dept_age(Sdept,Avg_age)
SELECT Sdept,AVG(age)
GROUP BY Sdept;
例3.73:将学生201215121的年龄改为22岁(修改某一个元组的值)
UPDATE student
SET Sage=22
WHERE Sno='201215121';
例3.74:将所有学生的年龄增加1岁(修改多个元组的值)
UPDATE student
SET Sage=Sage+1;
例3.75:将计算机科学系全体学生的成绩置零(带子查询的修改语句)
UPDATE sc
SET Grade=0
WHERE Sno IN
(SELECT Sno
FROM student
WHERE Sdept='CS');
例3.76:删除学号为201215128的学生记录(删除某一个元组的值)
DELETE
FROM student
WHERE Sno='201215128';
例3.77:删除所有学生的选课记录(删除多个元组的值)
DELETE
FROM sc;
例3.78:删除计算机科学系所有学生的选课记录(带子查询的删除语句)
DELETE
FROM sc
WHERE Sno IN
(SELECT Sno
FROM student
WHERE Sdept='CS');
例3.81:从Student表中找出漏填了数据的学生信息(空值的判断:IS NULL,IS NOT NULL)
SELECT*
FROM student
WHERE Sname IS NULL OR Ssex IS NULL OR Sage IS NULL OR Sdept IS NULL;
例3.83:找出选修1号课程的不及格的学生以及缺考的学生(空值的算数运算、比较运算和逻辑运算)
SELECT Sno
FROM sc
WHERE Grade<60 AND Cno='1'
UNION
SELECT Sno
FROM sc
WHERE Grade IS NULL AND Cno='1';
/*等于*/
SELECT Sno
FROM sc
WHERE Cno='1' AND (Grade<60 OR Grade IS NULL);
例3.85:建立信息系学生的视图(建立视图)
CREATE VIEW IS_Student
AS
SELECT Sno,Sname,Sage
FROM student
WHERE Sdept='IS'
WITH CHECK OPTION;
例3.86:建立信息系选修了1号课程的学生的视图(包括学号、姓名、成绩)(行列子集视图)
CREATE VIEW IS_S1(Sno,Sname,Grade)
AS
SELECT student.Sno,Sname,Grade
FROM student,sc
WHERE Sdept='IS'AND
student.Sno=sc.Sno AND
sc.Cno='1';
例3.87:建立信息系选修了1号课程且成绩在90分以上的学生的视图(视图可以建立在一个已知视图上)
CREATE VIEW IS_S2
AS
SELECT Sno,Sname,Grade
FROM IS_S1/*信息系选修了1号课程的学生*/
WHERE Grade>90;
例3.88:定义一个反映学生出生年份的视图(带虚拟列的视图)
CREATE VIEW BT_S(Sno,Sname,Sbirth)
AS
SELECT Sno,Sname,2014-Sage
FROM Student;
输出结果:
例3.89:将学生的平均成绩定义为一个视图(分组视图)
CREATE VIEW S_G(Sno,Gavg)
AS
SELECT Sno,AVG(Grade)
From SC
GROUP BY Sno;
输出结果:
例3.91:删除视图BT_S和视图IS_S1(删除视图)
DROP VIEW BT_S;/*成功执行*/
DROP VIEW IS_S1;/*拒绝执行*/
/*由于IS_S1还定义了视图IS_S2,所以要采用级联删除*/
DROP VIEW IS_S1 CASCADE;
例3.92:在信息系学生的视图中找出年龄小于20岁的学生(视图查询与视图消解)
SELECT Sno,Sage
FROM is_student
WHERE Sage<20;
视图消解:从数据字典中找到视图的定义,再把定义中的子查询与用户的查询结合起来,转换成等价的对基本表的查询。
本例转换后的查询语句为:
SELECT Sno,Sage
FROM student
WHERE Sdept='IS' AND Sage<20;
例3.94:在S_G视图(学生的平均成绩视图)中查询平均分在90分以上的学生的学号和平均成绩(WHERE子句不能用聚集函数作为条件表达式)
SELECT *
FROM S_G
WHERE Gavg>=90;
本例转换后的查询语句为:(这种写法是错误的!)
SELECT Sno,AVG(Grade)
FROM SC
WHERE AVG(Grade>=90)
GROUP BY Sno;
正确的写法为:
SELECT Sno,AVG(Grade)
FROM SC
GROUP BY Sno
HAVING AVG(Grade>=90);
也可以写为:
SELECT *
FROM (SELECT Sno,AVG(Grade)
FROM sc
GROUP BY Sno)AS S_G(Sno,Gavg)
WHERE Gavg>=90;
例3.95:将信息系学生视图IS_Student中学号为“201215122”的学生姓名改名为“刘辰”。(更新视图:同时会更新基本表)
UPDATE IS_Student
SET Sname='刘辰'
WHERE Sno='201215122';
转换后的语句:
UPDATE Student
SET Sname='刘辰'
WHERE Sno='201215122' AND Sdept='IS';
例3.97:删除信息系学生视图IS_Student中学号为“201215129”的记录
DELETE
FROM is_student
WHERE Sno='201215129';
/*转换后*/
DELETE
FROM Student
WHERE Sno='201215129' AND Sdept='IS';
到这里,我觉得我以后复习还要看的题目,就全部结束了。感谢您的阅读。爱您!笔芯!❥(^_-)