语句格式:
1 | SELECT [ALL|DISTINCT] 目标列表达式,目标类表达式 |
单表查询
选择表中的若干列
查询指定列
格式:在SELECT后面加列名,FROM后面加表名
查询全体学生的学号和姓名:
1 | SELECT Sno,Sname FROM Student; |
查询全体学生的姓名、学号、所在系:
1 | SELECT Sno,Sname,Sdept FROM Student; |
查询所有列
格式:在SELECT后面列出所有列名或为*
查询全体学生的详细记录:
1 | SELECT Sno,Sname,Ssex,Sage,Sdept FROM Student; |
查询经过计算的值
选出表中指定的属性列,并经过计算后输出。
格式:SELECT子句的目标列表达式可以为:
- 算术表达式:+、-、*、➗
- 字符串常量:张三∪李四
- 函数:平均值,最大值之类的
- 列别名:直接现实学号这俩字儿,不显示数据
查询全体学生的姓名及其出生年龄:
1 | SELECT Sname,2004-Sage FROM Student; |
| Sname | 2004-Sage |
|---|---|
| 李勇 | 1984 |
| 刘晨 | 1985 |
| 王敏 | 1986 |
| 张立 | 1985 |
查询全体学生的姓名、出生年份和所有系,要求用小写字母表示所有系名:
1 | SELECT Sname,'Year of Birth: ',2004-Sage,LOWER(Sdept) FROM Student; |
| Sname | ‘Year of Birth:’ | 2014-Sage | LOWER(Sdept) |
|---|---|---|---|
| 李勇 | Year of Birth: | 1994 | cs |
| 刘晨 | Year of Birth: | 1995 | cs |
| 王敏 | Year of Birth: | 1996 | ma |
| 张立 | Year of Birth: | 1995 | is |
| 使用列别名改变查询结果的列标题: |
1 | SELECT Sname NAME, 'Year of Birth: ' BIRTH,2004-Sage BIRTHDAY,LOWER(Sdept) DEPARTMENT FROM Student; |
| NAME | BIRTH | BIRTHDAY | DEPARTMENT |
|---|---|---|---|
| 李勇 | Year of Birth: | 1994 | cs |
| 刘晨 | Year of Birth: | 1995 | cs |
| 王敏 | Year of Birth: | 1996 | ma |
| 张立 | Year of Birth: | 1995 | is |
选择表中若干元组(行)
消除取值重复的行
如果没有指定DISTINCT关键词,自动为ALL。
查询选修了课程的学生学号:
1 | SELECT Sno FROM SC; |
等价于:
1 | SELECT ALL Sno FROM SC; |
输出结果为:
| Sno |
|---|
| 200215121 |
| 200215121 |
| 200215121 |
| 200215122 |
| 200215122 |
指定DISTINCT关键词,去掉表中重复的行: |
1 | SELECT DISTINCT Sno FROM SC; |
| Sno |
|---|
| 200215121 |
| 200215122 |
查询满足条件的元组
用WHERE来实现
| 查询条件 | 谓词 |
|---|---|
| 比较 | =, >, <, >=, <=, !=, <>, !>, !<;NOT + 上述比较符 |
| 确定范围 | BETWEEN AND, NOT BETWEEN AND |
| 确定集合 | IN, NOT IN |
| 字符匹配 | LIKE, NOT LIKE |
| 空值 | IS NULL, IS NOT NULL |
| 多重条件(逻辑运算) | AND, OR, NOT |
比较大小
显示所有计算机科学系CS全体学生的名字:
1 | SELECT Sname FROM Student WHERE Sdept = "CS"; |
查询所有年龄在20岁以下的学生姓名及其年龄:
1 | SELECT Sname,Sage FROM Student WHERE Sage<20; |
查询考试成绩有不及格的学生的学号:
1 | SELECT DISTINCT Sno FROM SC WHERE Grade<60; |
确定范围
谓词:BETWEEN...AND...和NOT BETWEEN...AND...
查询年龄在20~23岁(包含20和23)之间的学生姓名、系别、年龄:
1 | SELECT Sname,Sdept,Sage |
查询年龄不在20~23岁之间的学生姓名、系别、年龄:
1 | SELECT Sname,Sdept,Sage |
确定集合
谓词:IN,NOT IN
查询信息系(IS)、数学系(MA)和计算机系(CS)学生的姓名和性别:
1 | SELECT Sage, Ssex FROM Student |
查询既不是信息系(IS)、数学系(MA)和计算机系(CS)学生的姓名和性别:
1 | SELECT Sage,Ssex FROM Student |
字符查询
谓词:[NOT] LIKE '匹配串' [ESCAPE '换码字符']
查询所有姓刘学生的姓名、学号和性别:
1 | SELECT Sname,Sno,Ssex FROM Student WHERE Sname LIKE '刘%'; --%代表任意长度字符串-- |
查询姓“欧阳”且全名为三个汉字的学生和姓名:
1 | SELECT Sname FROM Student WHERE Sname LIKE '欧阳_'; --_代表任意一个字符-- |
查询名字中第二个字为“阳”字的学生的姓名和学号:
1 | SELECT Sname,Sno FROM Student WHERE Sname LIKE '_欧%' ; |
查询所有不姓刘的学生姓名、学号和性别:
1 | SELECT Sname,Sno,Ssex FROM Student WHERE Sname NOT LIKE '刘%'; |
如果要查询的字里面带_的话,可以使用\来变为字符
涉及空值的查询
谓词:IS NULL,IS NOT NULL
某些学生选修课程后没有参加考试,所以有选课记录但是没有考试成绩。查询缺少成绩学生的学号和相应的课号:
1 | SELECT Sno,Cno FROM SC WHERE Grade IS NULL; |
查询所有有成绩的学生的学号:
1 | SELECT Sno,Cno FROM SC WHERE Grade IS NOT NULL; |
多重条件的查询
用AND和OR来连接条件,AND的优先级高于OR。
查询计算机系年龄在20岁以下的学生姓名:
1 | SELECT Sname FROM Student WHERE Sdept = 'CS' AND Sage<20; |
查询信息系(IS)、数学系(MA)、计算机系(CS)学生的姓名和性别:
1 | SELECT Sname,Ssex FROM Student WHERE Sdept IN('IS','MA','CS') |
ORDER BY排序
- 可以按照一个属性或者多个属性排序
ASC升序DESC降序- 默认升序
- 空值默认最大值
查询选修了3号课程的学生的学号及其成绩,查询结果按分数降序:
1 | SELECT Sno,Grade FROM SC WHERE Cno = "3" ORDER BY Grade DESC; |
查询全体学生情况,查询结果按所在系的系号进行升序排序,同一系的按年龄降序:
1 | SELECT * FROM Student ORDER BY Sdept, Sage; |
聚集函数
WHERE子句是不能用聚集函数的,聚集函数只能用在SELECT后面以及GROUP BY中的HAVING子句中
| 函数语法 | 功能说明 |
|---|---|
COUNT([DISTINCT|ALL] *) |
统计元组个数 |
COUNT([DISTINCT|ALL] <列名>) |
统计一列中值的个数 |
SUM([DISTINCT|ALL] <列名>) |
计算一列值的总和(此列必须是数值型) |
AVG([DISTINCT|ALL] <列名>) |
计算一列值的平均值(此列必须是数值型) |
MAX([DISTINCT|ALL] <列名>) |
求一列值的最大值 |
MIN([DISTINCT|ALL] <列名>) |
求一列值的最小值 |
ALL是默认值,所有符合的值都会运行函数DISTINCT去重,符合的值只会进行一次函数
查询学生的总人数:
1 | SELECT COUNT(*) FROM Student; |
查询选修了课程的学生人数:
1 | SELECT COUNT (DISTINCT Sno) FROM SC; |
查询学生200215012选修课程的总学分数:
1 | SELECT SUM(Ccredit) FROM SC, Course WHERE Sno = '200215012' AND SC.Cno = Course.Cno; |
计算1号课程的平均成绩:
1 | SELECT AVG(Grade) FROM SC WHERE Cno = '1'; |
查询选修1号课程的学生最高分数:
1 | SELECT MAX(Grade) FROM SC WHERE Cno = '1'; |
GROUP BY子句
GROUP BY子句作用:按一列或多列的值分组,值相等的为一组,来细化聚集函数的作用对象。比如我想要大于平均成绩的学生的名字。
- 未分组,聚集函数对象是整个查询结果
- 分组,聚集函数对象是每个组
求各个课程号以及相应的选课人数:
1 | SELECT Cno,COUNT(Sno) FROM SC GROUP BY Cno; |
| Cno | COUNT(Sno) |
|---|---|
| 1 | 22 |
| 2 | 34 |
| 3 | 44 |
| 4 | 33 |
| 5 | 48 |
先按照一个一个Cno分成多个组,然后每个组依次SELECT和COUNT👍。并且GROUP BY子句分组后,可以使用HAVING语句选定筛选条件,把组再筛选一遍。
查询选修了3门以上课程的学生学号:
1 | SELECT Cno FROM SC GROUP BY Sno HAVING COUNT (*) > 3; |
其实这时候我们就会发现了,分成多个表后,Cno无论如何还是只会输出一个,因为有一条铁律:GROUP BY 后面写了谁,SELECT 就只能查谁 + 聚合函数(COUNT/SUM/MAX 等)
连接查询
等值与非等值连接查询
连接查询的WHERE子句中用来连接两个表的条件称为连接条件或连接谓词,格式如下两种:
等值情况下会形成一个自然连接的笛卡尔积表,不过只做查询,查询完就没了
1 | 表名1.列名1 比较运算符 表名2.列名2; |
1 | 表名1.列名1 BETWEEN 表名2.列名2 AND 表名2.列名3; |
查询每个学生及其选修课程的情况:
1 | SELECT Student.*,SC.* |
| Student.Sno | Sname | Ssex | Sage | Sdept | SC.Sno | Cno | Grade |
|---|---|---|---|---|---|---|---|
| 200215121 | 李勇 | 男 | 20 | CS | 200215121 | 1 | 92 |
| 200215121 | 李勇 | 男 | 20 | CS | 200215121 | 2 | 85 |
| 200215121 | 李勇 | 男 | 20 | CS | 200215121 | 3 | 88 |
| 200215122 | 刘晨 | 女 | 19 | CS | 200215122 | 2 | 90 |
| 200215122 | 刘晨 | 女 | 19 | CS | 200215122 | 3 | 80 |
自身连接
一个表与其自身进行连接。
- 需要给表起个别名
- 用属性记得加前缀
查询每一门课的间接先修课:
为Course表取两个别名,一个是FIRST,一个是SECOND
FIRST 和 SECOND 表(Course 表)两个长得一样
| Cno | Cname | Cpno | Ceredit |
|---|---|---|---|
| 1 | 数据库 | 5 | 4 |
| 2 | 数学 | 2 | |
| 3 | 信息系统 | 1 | 4 |
| 4 | 操作系统 | 6 | 3 |
| 5 | 数据结构 | 7 | 4 |
| 6 | 数据处理 | 2 | |
| 7 | PASCAL 语言 | 6 | 4 |
| 什么是简介选修课?比如数据库的简介选修课就是PASCAL语言,1->5->7.🤔你是不是觉得,欸我超这个该怎么弄,其实很简单,我们只需要在第一个表找到前缀课,然后再到第二表找前缀课的前缀课就好了👍。 |
1 | SELECT FIRST.Cno, SECOND.Cpno |
| Cno | Pcno |
|---|---|
| 1 | 7 |
| 3 | 5 |
| 5 | 6 |
外连接
还记得我们之前讲的悬浮元组吗🤔点我回去复习
外连接分为:
左外连接:列出左边关系中所有元组
1 | LEFT OUT JOIN SC ON; |
右外连接:列出右边关系中所有元组
1 | RIGHT OUT JOIN SC ON; |
查询每个学生及其选修课程情况:
1 | SELECT Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade |
用外连接查询可改为:
1 | SELECT Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade |
| Student.Sno | Sname | Ssex | Sage | Sdept | Cno | Grade |
|---|---|---|---|---|---|---|
| 200215121 | 李勇 | 男 | 20 | CS | 1 | 92 |
| 200213121 | 李勇 | 男 | 20 | CS | 2 | 85 |
| 200215121 | 李勇 | 男 | 20 | CS | 3 | 88 |
| 200215122 | 刘晨 | 女 | 19 | CS | 2 | 90 |
| 200215122 | 刘晨 | 女 | 19 | CS | 3 | 80 |
| 200215123 | 王敏 | 女 | 18 | MA | NULL | NULL |
| 200215125 | 张立 | 男 | 19 | IS | NULL | NULL |
它会把不匹配的也加进去,没有的话就变为NULL。
多表连接
两个以上的表连接,之前讲的都是两个表连接
查询每个学生的学号、姓名、选修的课程名及其成绩:
1 | SELECT Student.Sno, Sname,Cname,Grade |
也就是形成一个大表
嵌套查询
一个查询套着另一个查询。一个SELECT-FROM-WHERE语句被称为一个查询。
- 只能嵌套在
WHERE或者HAVING里面 - 外层查询(父查询)、内层查询(子查询)
- 子查询不准使用
ORDER BY排序
当然具体要用的话,也可以用上面的连接来替代,主要看你怎么想了。
带有IN谓词的子查询
查询与“刘晨”在同一个系学习的学生:
1 | SELECT Sno,Sname,Sdept FROM Student |
| Sno | Sname | Sdept |
|---|---|---|
| 200215121 | 李勇 | CS |
| 200215122 | 刘晨 | CS |
查询选修了课程名为“信息系统“的学生学号和姓名:
1 | SELECT Sno,Sname FROM Student |
但是这个用连接写其实挺少的:
1 | SELECT Sno,Sname |
带有比较运算符的子查询
查询与”刘晨“在同一个系学习的学生:
1 | SELECT Sno.Sname,Sdept |
因为系肯定只有一个,所以可以换成等号=:
1 | SELECT Sno.Sname,Sdept |
找出每个学生超过他选修课程平均成绩的课程号:
1 | SELECT Sno,Cno |
上面这个你也许会看不懂,这个和之前的查询过程不太一样,是先执行的父查询,选出一行,然后丢进子查询。子查询完毕后再返回父查询获得结果。
带有ANY(SOME)或ALL谓词的子查询
谓语语义:
ANY:任意一个值All:所有值
需要搭配比较运算符使用:
| 谓词 | 含义说明 |
|---|---|
> ANY |
大于子查询结果中的某个值 |
> ALL |
大于子查询结果中的所有值 |
< ANY |
小于子查询结果中的某个值 |
< ALL |
小于子查询结果中的所有值 |
>= ANY |
大于等于子查询结果中的某个值 |
>= ALL |
大于等于子查询结果中的所有值 |
<= ANY |
小于等于子查询结果中的某个值 |
<= ALL |
小于等于子查询结果中的所有值 |
= ANY |
等于子查询结果中的某个值 |
= ALL |
等于子查询结果中的所有值(通常无意义) |
!= ANY / <> ANY |
不等于子查询结果中的某个值 |
!= ALL / <> ALL |
不等于子查询结果中的所有值 |
查询非计算机科学系中比计算机科学任意一个学生年龄小的学生姓名和年龄:
1 | SELECT Sname,Sage |
当然啦,聚集函数也可以实现:
1 | SELECT Sname,Sage |
查询非计算机科学系中比计算机科学所有学生年龄小的学生姓名和年龄:
1 | SELECT Sname,Sage |
当然啦,聚集函数也可以实现desuwa:
1 | SELECT Sname,Sage |
聚集函数效率要高一点,能用聚集函数就用聚集函数吧
说些什么吧!