目录
[2.SELECT 语句基本语法](#2.SELECT 语句基本语法)
[⑧前 N 行](#⑧前 N 行)
[(3)SELECT INTO 查询](#(3)SELECT INTO 查询)
[2.ORDER BY 子句](#2.ORDER BY 子句)
[3.GROUP BY 子句](#3.GROUP BY 子句)
[4.SQL 功能函数](#4.SQL 功能函数)
[3.使用 IN 或 Not in 的子查询](#3.使用 IN 或 Not in 的子查询)
[4.使用 Any 或 All的子查询](#4.使用 Any 或 All的子查询)
一、单表查询
1.概念
- 数据查询是数据库管理系统(Database Management System,DBMS)中一个最重要的功能,在数据库应用中,最常用的操作也是查询。
- 数据查询是指数据库管理系统按照数据库用户指定的条件,从数据库的相关表中找到满足条件的数据的过程。因此,数据查询涉及两个方面:一是用户指定查询条件,二是系统进行处理并把查询结果以用户需要的格式反馈给用户。
- 在 SQL Server 中,数据查询可以使用 SSMS 的图形化界面,也可以使用 T-SQL 查询语句来实现。
2.SELECT 语句基本语法
SELECT 语句是 T-SQL 的核心语句,其基本语法格式如下所示
SELECT <检索内容> [AS <别名>] [INTO <目标表名>]
FROM <源表名>
[WHERE <检索条件>]
[GROUP BY <分类字段> [ HAVING <检索条件>]]
[ORDER BY<排序字段> [ASC | DESC]]
3.实战训练
(1)选择列
①所有列
-
查询表中的数据列时,最简单的是查询表中的所有数据,只需要 SELECT 和 FROM 两关键字即可。
-
要把表中所有列和列数据显示出来,可以使用符号 "*",它表示所有列。
-
此时,SELECT 语句的基本格式为
SELECT * FROM 表名
【实战训练】在 SCC 数据库中,查询 Student 表中所有学生的详细信息
任务实施:该操作是要查询 Student 表中的所有列,所以也叫全表查询。
USE SCC SELECT * FROM Student
②指定列
-
查询指定的列时,将需要显示的列名在 SELECT 后依次列出来。
-
此时,SELECT 语句的基本格式为:
SELECT <字段列表> FROM 表名
字段列表中的列名之间用英文逗号隔开,而且列名的先后顺序决定了结果集显示的顺序。若将表中所有的列名都放在这个列表中,将查询整个表的数据,使用 "*" 的效果相同。
【实战训练 】查询 Student 表中所有学生的学号、姓名和性别
任务实施:该操作是要查询学生的学号(Sno)、姓名(Sname)和性别(Sex),数据都来自 Student 表。代码如下:
SELECT Sno, Sname, Sex FROM Student
③计算列
【实战训练】查询 Score 表中所有学生的学号、课程编号和总成绩。
说明:总成绩 = 平时成绩40%+ 期末成绩60%
任务实施:在 Score 表中存储有学生选修课程的平时成绩(Uscore)和期末成绩(Endscore),由此可以计算出总成绩。代码如下:
SELECT Sno, Cno, Uscore*0.4+Endscore*0.6 FROM Score
④使用别名
使用别名时有以下三种方法:
- 列名在前,别名在后,中间用空格隔开,即通过 "列名 别名" 的形式。
- 列名和别名之间用 AS 连接,即通过 "列名 AS 别名" 的形式。
- 别名等于列名,即通过 "别名 = 列名" 的形式。
【实战训练 】查询 Score 表中所有学生的学号、课程编号和总成绩,结果显示为学号、课程编号和总成绩的中文别名
任务实施:代码如下:
-- 第一种格式书写代码: SELECT Sno 学号,Cno 课程编号, Uscore*0.4+Endscore*0.6 总成绩 FROM Score --第二种格式书写代码,代码如下: SELECT Sno AS 学号,Cno AS 课程编号, Uscore*0.4+Endscore*0.6 AS 总成绩 FROM Score --第三种格式书写代码,代码如下: SELECT 学号=Sno,课程编号=Cno,总成绩= Uscore*0.4+Endscore*0.6 FROM Score
(2)选择行
①满足条件的行
语法格式:
SELECT <字段列表> FROM 表名 WHERE 条件表达式
作用 :在查询表数据时,通过WHERE后的条件表达式(如年龄>18、性别='男'),只返回符合条件的数据行,实现精准数据筛选。

②简单条件查询
【实战训练】查询 Student 表中所有男生的详细信息。
SELECT * FROM Student WHERE Sex='男'
③复合条件查询
【实战训练 】查询 Score 表中有不及格现象的学生信息。
SELECT * FROM Score WHERE Uscore<60 Or Endscore<60【实战训练 】查询 Student 表中出生于 2000 年的所有男生的信息。
SELECT * FROM Student WHERE Sex='男' and Year(Birth)=2000【实战训练 】查询学分在 1~2 学分之间的课程编号和课程名和学分。
SELECT Cno, Cname, Credit FROM Course WHERE Credit between 1 and 2(等价于:
Credit>=1 and Credit<=2)
④指定集合查询
【实战训练 】查询选修了 C001、C002 和 C003 三门课程任一门的学生学号、课程编号和期末成绩。
SELECT Sno, Cno, Endscore FROM Score WHERE Cno In('c001', 'c002', 'c003')
⑤模糊查询
【实战训练 】查询所有姓 "陈" 学生的基本信息。
SELECT * FROM Student WHERE Sname Like '陈%'说明:
- %(百分号):代表任意长度的字符串。比如,'a%' 代表以字符 a 开头的任意长度的字符串。
- (下横线):代表任意单个字符。比如,'a' 代表以字符 a 开头的长度为 2 的字符串。
【实战训练 】查询名字中只有两个汉字的学生的基本信息。
SELECT * FROM Student WHERE Sname Like '__'
⑥空值查询
【实战训练】在 Score 表中查询期末有缺考现象的学生信息。
SELECT * FROM Score WHERE Endscore IS NULL
⑦消除重复行!
【实战训练】查询有选课记录的学生的学号,如果一个学生选修了多门课程,只需要显示一次学号。
-- (普通查询,会显示重复学号):
SELECT Sno FROM Score
-- (去重查询)
SELECT Distinct sno FROM Score
⑧前 N 行
【实战训练 】查询 Course 表中前 5 门课程的详细信息。任务实施:在 SELECT 子句中利用关键字 Top 限制返回到结果集中的行数,其基本语法如下:
Top n [Percent]其中,n 指定返回的行数,如果未指定 Percent,n 就是返回的行数。如果指定了 Percent,n 就是返回的结果集行数的百分比。本例代码:
SELECT Top 5 * FROM Course
(3)SELECT INTO 查询
可以把任何查询结果集放置到一个新表中,语法格式为:
SELECT 字段列表 INTO 新表名
FROM 源表名
WHERE 条件表达式
【实战训练】查询student表中男生的详细信息,并将结果保存到临时表"Boys"中
此处使用SELECT INTO语句把查询的结果存放到临时表。代码如下:
SELECT * INTO Boys FROM student WHERE sex = ' 男 '语句执行后,结果显示有"19行受影响",为了更加直观显示临时表数据,可以通过查询语句观察结果,代码如下:
SELECT * FROM Boys
二、分组统计查询
SELECT 语句基本语法:SELECT 语句是 T-SQL 的核心语句,其基本语法格式如下所示:
SELECT <检索内容> [AS < 别名 >] [INTO < 目标表名 >]
FROM < 源表名 >
[WHERE < 检索条件 >]
[GROUP BY < 分类字段 > [ HAVING < 检索条件 >]]
[ORDER BY < 排序字段 > [ASC | DESC]]
1.常用的聚合函数
聚合函数用于计算表中的数据,返回单个计算结果。

2.ORDER BY 子句
可以使用 ORDER BY 子句对查询结果集排序。ORDER BY 子句可以将查询结果按一个或多个列的值的大小顺序输出。在 ORDER BY 子句中用 ASC 关键字表示升序,DESC 关键字表示降序,默认情况为升序。
3.GROUP BY 子句
GROUP BY 子句可以将查询结果表的各行按某一列或多列取值相等的原则进行分组,然后使用集合函数对记录组进行操作。
4.SQL 功能函数

5.实战训练
(1)简单统计查询
【实战训练 】查询 Student 表中学生的总人数
SELECT Count(sno) AS 学生人数 FROM Student也可以使用如下代码,执行结果是相同的:
SELECT Count(*) AS 学生人数 FROM Student
【实战训练】查询学生 "s013180302" 的期末总成绩和平均成绩
SELECT Sum(Endscore) AS 总成绩 , Avg(Endscore) AS 平均成绩 FROM Score WHERE Sno='s013180302'
【实战训练】查询课程 "c001" 的期末最高成绩和最低成绩
SELECT Max(Endscore) AS 最高成绩 , Min(Endscore) AS 最低成绩 FROM Score WHERE Cno='C001'
【实战训练】查询 Student 表中学生的学号从第 2 位开始的 7 个字符
SELECT substring(sno,2,7) FROM Student
【实战训练 】查询每个学生的期末成绩,对成绩中的小数进行四舍五入
SELECT Sno 学号,Cno 课程号,Round(Endscore,0) 期末成绩 FROM Score
(2)查询结果排序
【实战训练 】查询每个学生的期末总成绩,结果按照降序排序输出。
SELECT Sno 学号, Sum(Endscore) 总成绩 FROM Score GROUP BY sno ORDER BY sum(endscore) DESC
(3)分组统计查询
【实战训练 】查询 Student 表中男、女生人数,要求使用中文别名。
SELECT Sex 性别, Count(*) 学生人数 FROM Student GROUP BY sex
【实战训练 】查询 Student 表中男生的人数,要求使用中文别名。
SELECT Sex 性别, Count(*) 学生人数 FROM Student GROUP BY Sex HAVING sex='男'
【实战训练】在 Score 表中,查询期末平均成绩在 80 分以上的学生的学号和平均成绩,查询结果按照平均成绩降序排序。
SELECT Sno 学号, Avg(Endscore) 平均成绩 FROM Score GROUP BY Sno HAVING Avg(Endscore)>=80 ORDER BY Avg(Endscore) DESC
(4)提示
- 聚合函数不能用在 WHERE 子句中,也就是说 WHERE 子句后面的条件表达式不能出现聚合函数,而聚合函数可以用于 GROUP BY 子句中的 HAVING 子句中。
- WHERE 子句与 HAVING 子句的根本区别在于作用对象不同。WHERE 子句作用于基本表或者视图,从中选择满足条件的记录。HAVING 子句作用于组内,从中选择满足条件的记录。
三、多表查询
1.知识准备
数据查询时,用户需要查询的数据有时并不都在一个数据表中,可能涉及一个以上的表,这时就要使用多表查询。多表查询是指将多个表连接在一起的查询,也叫连接查询。连接查询是关系数据库中最主要的查询,主要包括内连接、外连接和交叉连接等,通过连接运算符可以实现多个表的查询。
2.内连接
内连接是一种最常用的连接类型。使用内连接时,如果两个表的相关字段满足连接条件,就从这两个表中提取数据并组合成新的记录,也就是在内连接查询中,只有满足条件的元组才能出现在结果集中。图 15-1 为内连接关系示意图。实现内连接查询时,SELECT 语句有两种格式。

-- 格式 1:
SELECT <字段列表>
FROM <表名1>,<表名2>
WHERE <表名1.列名=表名2.列名> [AND 条件表达式]
-- 格式 2:
SELECT <字段列表>
FROM <表名1> INNER JOIN <表名2> ON <表名1.列名=表名2.列名>
[WHERE 条件表达式]
【实战训练】查询所有学生的学号、姓名、课程编号、平时成绩和期末成绩。
SELECT Student.sno,sname,cno,uscore,endscore FROM Student INNER JOIN Score ON Student.sno=Score.sno
【实战训练】查询所有男生的学号、姓名、课程编号、平时成绩和期末成绩。
SELECT Student.sno,sname,cno,uscore,endscore FROM Student INNER JOIN Score ON Student.sno=Score.sno WHERE sex='男'
【实战训练】查询所有学生的学号、姓名、课程名称、平时成绩和期末成绩。
SELECT Student.sno,sname,cname,uscore,endscore FROM Student INNER JOIN Score ON Student.sno=Score.sno INNER JOIN Course ON Score.cno=Course.cno
【实战训练】查询每门课程的课程编号、课程名称及其选课人数。
SELECT Score.cno 课程编号,cname 课程名称,count(*) 选课人数 FROM Score join Course on Score.cno=Course.cno GROUP BY Score.cno,cname
3.外连接
外连接通常用于相连接的表中至少有一个表需要显示所有数据行的情况,因此外连接的结果集中不但包含满足连接条件的记录,还包含相应表中的所有记录,即某些记录即使不满足连接条件,但仍需要输出。外连接分为左外连接、右外连接和全外连接三种。
(1)左外连接
实现左外连接查询时,SELECT 语句的语法格式为:
SELECT <字段列表>
FROM <表名1> LEFT [OUTER] JOIN <表名2> ON <表名1.列名=表名2.列名>

(2)右外连接
实现右外连接查询时,SELECT 语句的语法格式为:
SELECT <字段列表>
FROM <表名1> RIGHT [OUTER] JOIN <表名2> ON <表名1.列名=表名2.列名>

(3)全外连接
实现全外连接查询时,SELECT 语句的语法格式为:
SELECT <字段列表>
FROM <表名1>FULL JOIN <表名2> ON <表名1.列名=表名2.列名>

(4)实战训练
【实战训练】查询 Student 表中每个学生的课程选修情况,结果显示为学号、姓名、课程编号和课程成绩。
SELECT Student.sno,sname,cno,uscore,endscore FROM Student LEFT JOIN Score ON Student.sno=Score.sno
【实战训练】查询每门课程的选修情况,结果显示为课程号、课程名和课程成绩。
SELECT Course.cno,cname,uscore,endscore FROM Score RIGHT JOIN Course ON Course.cno=Score.cno
【实战训练】将学生信息表 Student 与成绩表 Score 进行全外连接,结果显示为学号、姓名、课程号和课程成绩。
全外连接使用关键词 FULL JOIN,结果集中包括了所有连接表的所有行,不论它们是否匹配。当某条记录在另一个表中没有匹配记录时,则该表的相应列显示为 NULL。代码如下:
SELECT Student.sno,sname,cno,uscore,endscore FROM Student FULL JOIN Score ON Student.sno=Score.sno
4.交叉连接
连接查询中还有一种特殊情况,即迪卡尔积连接。两个表的迪卡尔积是两个表中记录的交叉乘积,即其中一个表中的每一个记录都要与另一个表中的每一个记录拼接,返回结果的行数等于两个表行数的乘积,因此结果表往往很大。实现交叉连接查询时,SELECT 语句的语法格式为:
SELECT <字段列表>
FROM <表名1>CROSS JOIN <表名2>
【实战训练】将学生信息表 Student 与成绩表 Score 进行交叉连接。
SELECT * FROM Student CROSS JOIN Score
5.自身连接
如果在一个连接查询中,涉及的两个表都是同一张表,这种查询称为自身连接查询。自身连接是指将一个表与它自身连接,将表如同分身一样分成两个,使用不同的别名,成为两个独立的表。自身连接是一种特殊的内连接,它是指相互连接的表在物理上为同一张表,但可以在逻辑上分为两张表。
SELECT <字段列表>
FROM <表名> AS <别名1> JOIN <表名> AS <别名2>
ON <别名1.列名=别名2.列名> and [筛选条件]
【实战训练】查询比 "陈天明" 年龄小的学生信息,结果显示为学号、姓名、性别和出生年月,并按照出生年月升序排序。
任务实施:若要在一个表中查找具有相同列值的行,则可以使用自身连接。使用自身连接时需为表指定两个别名,比如 a 和 b,且对所有列的引用均要用别名限定。代码如下:
SELECT b.sno,b.sname,b.sex,b.birth FROM Student AS a JOIN Student AS b ON a.sname='陈天明' and a.birth<b.birth ORDER BY b.birth
【实战训练 】查询同时选修课程编号为 C001 和 C002 的学生的学号。
任务实施:本查询涉及的数据均来自 Score 表,此处采用自身连接完成查询操作。代码如下:
SELECT b.sno FROM Score a JOIN Score b ON a.sno=b.sno and a.cno='C001' and b.cno='C002'
四、子查询
1.知识准备
(1)定义
在 SQL 查询中,一个 SELECT-FROM-WHERE 语句称为一个查询块,将一个查询块嵌套在另一个查询块中的查询称为子查询或者嵌套查询。被包含的查询语句称为子查询或内查询,包含子查询的语句称为父查询或者外部查询。SQL Server 允许多层嵌套查询,类似于程序设计中的循环嵌套,嵌套层次最多可达到 255 层。
(2)子查询的类型及其执行方式
(1)不相关子查询:当外查询与内查询的条件不相关时,称为不相关子查询。
(2)相关子查询:当外查询与内查询的条件相关时,称为相关子查询。在相关子查询中,其执行顺序是先执行外层,再执行内层。
格式如下:
Select
From
Where 字段 运算符/谓词 (子查询)
2.使用比较运算符的子查询
当能够确切地知道子查询的返回值只有一个时,可以直接使用比较运算符(=、>、>=、<、<=、!=)将父查询和子查询连接起来。此时,SELECT 语句的一般格式为:
SELECT <字段列表> FROM <表名>
WHERE <列名> 比较运算符 (子查询)
注意,为了区分主查询和子查询,子查询语句应加小括号。
3.使用 IN 或 Not in 的子查询
在嵌套查询中,子查询的结果往往不是一个单值而是一组值,即子查询的结果是一个集合,这种情况可以使用谓词 In(包含于)、Not in(不包含于)将父查询和子查询连接起来,以判断父查询的某个字段值是否在子查询的结果集中。此时,SELECT 语句的一般格式为:
SELECT <字段列表> FROM <表名>
WHERE <列名> [In |Not in] (子查询)
4.使用 Any 或 All的子查询
当子查询的结果为单一值时可以用比较运算符,但如果返回的是多值,需要用到谓词 Any(某个值)或者 All(所有值)。Any 或 All 谓词一般与比较运算符配合使用,这种情况下,SELECT 语句的一般格式为:
SELECT <字段列表> FROM <表名>
WHERE <列名> 比较运算符 [Any |All ] (子查询)

5.使用Exists的子查询
谓词 Exists 表示存在的意思,使用 Exists 的子查询返回 "真" 或者 "假" 两种结果。当查询结果非空时,返回真值,外层 WHERE 子句结果为真;当查询结果为空时,返回假值,外层 WHERE 子句结果为假。这种情况下,SELECT 语句的一般格式为:
SELECT <字段列表> FROM <表名>
WHERE Exists (子查询)
**补充说明:**本查询可以使用逻辑运算符 "=any" 代替谓词 "In",意思是等于子查询结果中的某个值。
6.实战训练
【实战训练】查询与 "王强" 同年出生的所有学生的基本信息
SELECT * FROM Student WHERE year(birth) = (SELECT year(birth) FROM Student WHERE sname='王强')
【实战训练】查询选修了 2 门及以上课程的学生的姓名
-- 方法 1(子查询): SELECT sname FROM Student WHERE sno In (SELECT sno FROM Score GROUP BY sno HAVING count(*)>=2) -- 方法 2(连接查询): SELECT sname FROM Student join Score on Student.Sno=Score.sno GROUP BY sname,Score.sno HAVING count(*)>=2
【实战训练】查询选修了 "数据库应用" 课程的学生姓名
-- 方法 1(子查询): SELECT sname FROM Student WHERE sno In (SELECT sno FROM Score WHERE cno= (SELECT cno FROM Course WHERE cname='数据库应用')) -- 方法 2(连接查询): SELECT Student.Sname FROM Student INNER JOIN Score ON Student.Sno = Score.Sno INNER JOIN Course ON Score.Cno = Course.Cno WHERE Course.Cname = '数据库应用' -- 方法 3(用 = any 代替 In): SELECT sname FROM Student WHERE sno =any (SELECT sno FROM Score WHERE cno= (SELECT cno FROM Course WHERE cname='数据库应用'))
【实战训练】查询比任一女生年龄都大的男生的学号、姓名和出生年月
思路:通过
all谓词或聚合函数Min(),筛选出出生日期早于所有女生的男生(出生日期越早,年龄越大)。补充说明:用聚合函数实现时,
Min(birth)可获取女生中最早的出生日期,效果与birth<all一致。-- 方法 1(用all谓词):
SELECT sno,sname,birth FROM Student
WHERE sex='男' and birth<all
(SELECT birth FROM Student WHERE sex='女')-- 方法 2(用聚合函数Min()):
SELECT sno,sname,birth FROM Student
WHERE sex='男' and birth<
(SELECT Min(birth) FROM Student WHERE sex='女')
【实战训练】查询至少选修了一门课程的学生姓名
思路:使用
Exists谓词,判断学生是否在成绩表(Score)中有对应的选课记录,存在则返回该学生。SELECT sno,sname FROM Student
WHERE Exists
(SELECT * FROM Score WHERE sno=Student.sno)
【实战训练】查询一门课也没有选修的学生姓名
思路:
Not Exists表示内查询结果为空时,外查询返回真值。通过该谓词筛选出成绩表中无对应记录的学生。SELECT sno,sname FROM Student
WHERE not exists
(SELECT * FROM Score WHERE sno=Student.sno)