2. SQL 数据查询
数据查询
1. SELECT 语句一般格式
语句格式:
SELECT [ALL|DISTINCT]
<目标列表达式> [别名] [,<目标列表达式> [别名]] …
FROM <表名或视图名> [别名] [ ,<表名或视图名> [别名]] …
[WHERE <条件表达式>]
[GROUP BY<列名1> [HAVING <条件表达式>]]
[ORDER BY <列名2> [ASC|DESC]
2. 单表查询
** 功能 : ** 对一个表的内容进行查询
2.1. 选择表中的若干列
(1)查询指定列
** 格式 :** 在SELECT 后面指定列名,FROM后面指定列所在的表名。
【例】查询全体学生的学号与姓名。
SELECT Sno,Sname
FROM Student;
【例】查询全体学生的姓名、学号、所在系。
SELECT Sname,Sno,Sdept
FROM Student;
(2)查询全部列
** 功能:**选出表中所有属性列。
** 格式:*在SELECT关键字后面列出所有列名或将<目标列表达式>指定为。
【例】查询全体学生的详细记录。
SELECT Sno,Sname,Ssex,Sage,Sdept
FROM Student;
//两种方式
SELECT *FROM Student;
(3)查询经过计算的值
** 功能:**选出表中指定的属性列,并经过计算后输出。
** 格式:**在SELECT子句的<目标列表达式>可以为:
- 算数表达式
- 字符串常量
- 函数
- 列别名
【例】 查全体学生的姓名及其出生年份。这里假定目前年份是2004年。
SELECT Sname,2004-Sage
FROM Student;
| Sname | 2004-Sage |
|---|---|
| 李永 | 1984 |
| 刘成 | 1985 |
| 张力 | 1986 |
【例】查询全体学生的姓名、出生年份和所有系,要求用小写字母表示所有系名,这里假定目前年份是2004年。
SELECT Sname,'Year of Birth: ', 2004-Sage, LOWER(Sdept)
FROM Student;
| Sname | Year of Birth: | (1) | (2) |
|---|---|---|---|
| 李永 | Year of Birth: | 1984 | cs |
| 刘成 | Year of Birth: | 1985 | ma |
| 张力 | Year of Birth: | 1986 | is |
【例】使用列别名改变查询结果的列标题。
SELECT Sname NAME, 'Year of Birth: ' BIRTH, 2000-Sage BIRTHDAY, LOWER(Sdept) DEPARTMENT
FROM Student;
| NAME | BIRTH | BIRTHDAY | DEPARTMENT |
|---|---|---|---|
| 李永 | Year of Birth: | 1984 | cs |
| 刘成 | Year of Birth: | 1985 | ma |
| 张力 | Year of Birth: | 1986 | is |
####2.2. 选择表中的若干元组(行)
(1)关键词 DISTINCT 消除取值重复的行,若没有指定DISTINCT关键词,则缺省为ALL。
【例】查询选修了课程的学生学号。
SELECT Sno FROM SC;
/*等价于:*/
SELECT ALL Sno FROM SC;
| Sno |
|---|
| 201215121 |
| 201215121 |
| 201215122 |
【例】查询选修了课程的学生学号。指定DISTINCT关键词,去掉表中重复的行。
SELECT DISTINCT Sno
FROM SC;
| Sno |
|---|
| 201215121 |
| 201215122 |
(2)查询满足条件的元组(行)
| 查询条件 | 谓词 |
|---|---|
| 比较 | =,>,<,>=,<=,!=,<>,!>,!<;NOT+上述比较运算符 |
| 确定范围 | BETWEEN AND,NOT BETWEEN AND |
| 确定集合 | IN,NOT IN |
| 字符匹配 | LIKE,NOT LIKE |
| 空值 | IS NULL,IS NOT NULL |
| 多次条件(逻辑运算) | AND,OR,NOT |
a. 比较
【例】查询计算机科学系全体学生的名单。
SELECT Sname
FROM Student
WHERE Sdept='CS';
【例】查询所有年龄在20岁以下的学生姓名及其年龄。
SELECT Sname,Sage
FROM Student
WHERE Sage < 20;
b. 确定范围
【例】查询年龄在20~23岁(包括20岁和23岁)之间的学生的姓名,系和年龄。
SELECT Sname,Sdept,Sage
FROM Student
WHERE Sage NOT BETWEEN 20 AND 23;
【例】查询年龄不在20~23岁之间的学生姓名、系别和年龄。
SELECT Sname,Sdept,Sage
FROM Student
WHERE Sage NOT BETWEEN 20 AND 23;
c. 确定集合
【例】查询信息系(IS)、数学系(MA)和计算机科学系(CS)学生的姓名和性别。
SELECT Sname,Ssex
FROM Student
WHERE Sdept IN ( 'IS','MA','CS' );
【例】查询既不是信息系、数学系,也不是计算机科学系的学生的姓名和性别。
SELECT Sname,Ssex
FROM Student
WHERE Sdept NOT IN ( 'IS','MA','CS' );
d. 字符匹配
** 【注意】 % 表示任意长度的字符, _ ** 表示一个字符。
【例】查询学号为201215121的学生的详细情况。
SELECT *
FROM Student
WHERE Sno LIKE '201215121';
/*等价于:*/
SELECT *
FROM Student
WHERE Sno = '201215121';
【例】查询所有姓刘学生的姓名、学号和性别。
SELECT Sname,Sno,Ssex
FROM Student
WHERE Sname LIKE '刘%';
【例】查询姓”欧阳”且全名为三个汉字的学生的姓名。
SELECT Sname
FROM Student
WHERE Sname LIKE '欧阳_';
** 【注意】使用换码字符’’将通配符转义为普通字符**
- ESCAPE ‘\’ 表示“ \” 为换码字符
【例】查询DB_Design课程的课程号和学分。
SELECT Cno,Ccredit
FROM Course
WHERE Cname LIKE 'DB\_Design' ESCAPE '\';
【注意】 这里使用ESCAPE ‘ ' 表示其中的’_’并不是占位符,而是实际存在的符号。
e. 空值
【例】某些学生选修课程后没有参加考试,所以有选课记录,但没有考试成绩。查询缺少成绩的学生的学号和相应的课程号。
SELECT Sno,Cno
FROM SC
WHERE Grade IS NULL;
【例】查所有有成绩的学生学号和课程号。
SELECT Sno,Cno
FROM SC
WHERE Grade IS NOT NULL;
f. 多重条件(逻辑运算)
** 逻辑运算符**
- AND和 OR来联结多个查询条件
- AND的优先级高于OR
- 可以用括号改变优先级
【例】 查询计算机系年龄在20岁以下的学生姓名。
SELECT Sname
FROM Student
WHERE Sdept= 'CS' AND Sage<20;
【例】查询信息系(IS)、数学系(MA)和计算机科学系(CS)学生的姓名和性别。
SELECT Sname,Ssex
FROM Student
WHERE Sdept IN ( 'IS','MA','CS' );
/*可改写为:*/
SELECT Sname,Ssex
FROM Student
WHERE Sdept= 'IS' OR Sdept= 'MA' OR Sdept= 'CS';
2.3. ORDER BY 子句
可以按一个或多个属性列排序:
- 升序:ASC;
- 降序:DESC;
- 缺省值为升序;
当排序列含空值时:(空值默认为最大值)
- ASC:排序列为空值的元组最后显示
- DESC:排序列为空值的元组最先显示
【例】查询选修了3号课程的学生的学号及其成绩,查询结果按分数降序排列。
SELECT Sno,Grade
FROM SC
WHERE Cno= '3'
ORDER BY Grade DESC;
【例】 查询全体学生情况,查询结果按所在系的系号升序排列,同一系中的学生按年龄降序排列。
SELECT *
FROM Student
ORDER BY Sdept,Sage DESC;
2.4. 聚合函数
- 计数
COUNT([DISTINCT|ALL] *)
COUNT([DISTINCT|ALL] <列名>) - 计算总和
SUM([DISTINCT|ALL] <列名>) - 计算平均值
AVG([DISTINCT|ALL] <列名>) - 最大最小值
MAX([DISTINCT|ALL] <列名>)
MIN([DISTINCT|ALL] <列名>)
【注意】DISTINCT 代表去掉重复。
【例】查询学生总人数。
SELECT COUNT(*)
FROM Student;
【例】查询选修了课程的学生人数。
SELECT COUNT(DISTINCT Sno)
FROM SC;
【例】计算2号课程的学生平均成绩。
SELECT AVG(Grade)
FROM SC
WHERE Cno= '2';
【例】查询学生201215121选修课程的总学分数。
SELECT SUM(Ccredit)
FROM SC, Course
WHERE Sno='201215121' AND SC.Cno=Course.Cno;
2.5. GROUP BY子句
** GROUP BY子句分组: 细化聚集函数的作用对象**
- 未对查询结果分组,聚集函数将作用于整个查询结果
- 对查询结果分组后,聚集函数将分别作用于每个组
- 作用对象是查询的中间结果表
- 按指定的一列或多列值分组,值相等的为一组
** HAVING短语与WHERE子句的区别:**
- 作用对象不同
- WHERE子句作用于基表或视图,从中选择满足条件的元组
- HAVING短语作用于组,从中选择满足条件的组。
【例】求各个课程号及相应的选课人数。
SELECT Cno,COUNT(Sno)
FROM SC
GROUP BY Cno;
【例】查询选修了2门以上课程的学生学号。
SELECT Sno
FROM SC
GROUP BY Sno
HAVING COUNT(*) >2;
3. 连接查询
** 连接查询:同时涉及多个表的查询**
**连接条件或连接谓词:用来连接两个表的条件 **
** 连接条件一般格式:**
- [<表名1>.]<列名1> <比较运算符> [<表名2>.]<列名2>
- [<表名1>.]<列名1> BETWEEN [<表名2>.]<列名2> AND [<表名2>.]<列名3>
** (1)等值与非等值连接查询 **
** a. 等值连接**
【例】 查询每个学生及其选修课程的情况。
SELECT Student.*,SC.*
FROM Student,SC
WHERE Student.Sno = SC.Sno;
** b. 自然连接:等值连接中去掉目标列中重复的属性列称为自然连接。**
【例】对上例用自然连接完成。
SELECT Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade
FROM Student,SC
WHERE Student.Sno = SC.Sno;
** c. 自身连接**
- 自身连接:一个表与其自己进行连接
- 需要给表起别名以示区别
- 由于所有属性名都是同名属性,因此必须使用别名前缀
【例】查询每一门课的间接先修课(即先修课的先修课)
SELECT FIRST.Cno,SECOND.Cpno
FROM Course FIRST,Course SECOND
WHERE FIRST.Cpno = SECOND.Cno;
**d. 外连接 **
** 普通连接与外连接的区别:**普通连接操作值输出满足连接条件的元组。
** 外连接:** 操作以指定表为连接主体,将主题表中不满足连接条件的元组一并输出。
左外连接:LEFT OUT JOIN SC ON
关键字从左表(table1)返回所有的行,即使右表(table2)中没有匹配。如果右表中没有匹配,则结果为 NULL。右外连接:RIGHT OUT JOIN SC ON
关键字从右表(table2)返回所有的行,即使左表(table1)中没有匹配。如果左表中没有匹配,则结果为 NULL。
[例]查询每个学生及其选修课程的情况。
SELECT Sno,SC.Cno,Grade,Course.Cno,Cname,Cpno,Ccredit
FROM SC LEFT JOIN Course ON (SC.Cno=Course.Cno);
/*LEFT JOIN 与 LEFT OUTER JOIN结果相同*/
SELECT Sno,SC.Cno,Grade,Course.Cno,Cname,Cpno,Ccredit
FROM SC LEFT OUTER JOIN Course ON (SC.Cno=Course.Cno);
** e. 多表连接**
【例】查询每个学生的学号、姓名、选修的课程名及成绩。
SELECT Student.Sno,Sname,Cname,Grade
FROM Student,SC,Course /*多表连接*/
WHERE Student.Sno = SC.Sno
and SC.Cno = Course.Cno;
** f. 嵌套查询**
- 一个SELECT-FROM-WHERE语句称为一个查询块。
- 将一个查询块嵌套在另一个查询块的WHERE子句或HAVING短语的条件中的查询称为嵌套查询。
【例】
SELECT Sname/*外层查询/父查询*/
FROM Student
WHERE Sno IN
(SELECT Sno /*内层查询/子查询*/
FROM SC
WHERE Cno= '2');
** 带有IN谓词的子查询**
【例】查询与“刘晨”在同一个系学习的学生。此查询要求可以分步来完成。
SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept IN
(SELECT Sdept
FROM Student
WHERE Sname= '刘晨');
【例】查询选修了课程名为“信息系统”的学生学号和姓名。
SELECT Sno,Sname /*③ 最后在Student关系中取出Sno和Sname*/
FROM Student
WHERE Sno IN
( SELECT Sno /*② 然后在SC关系中找出选修了3号课程的学生学号*/
FROM SC
WHERE Cno IN
( SELECT Cno /*① 首先在Course关系中找出 “信息系统”的课程号,为3号*/
FROM Course
WHERE Cname= '信息系统'
)
);