复试面试准备数据库,本文为知识点例题讲解,例题来源课上笔记
1. 定义与基础
1.1基本语法
- SELECT: 指定要查询的列。
- FROM: 指定要查询的表。
- WHERE: 可选,用于过滤记录。
SELECT
语句用于从表中查询数据,其基础格式如下:
SELECT 列名 FROM 表名 WHERE 条件 ORDER BY 排序顺序;
2. 基础查询
2.1 查询所有数据
SELECT * FROM 学生;
假设 学生
表数据如下:
学号 | 姓名 | 专业 |
---|---|---|
1 | 张三 | 软件 |
2 | 李四 | 网络 |
3 | 王五 | 软件 |
2.2 查询指定字段
SELECT 学号, 姓名
FROM 学生
WHERE 专业 = '软件';
必修课
表数据如下:
课号 | 课程名 |
---|---|
101 | 数据库 |
102 | 数据结构 |
101 | 数据库 |
列出软件专业全部学生的学号及姓名:
学号 | 姓名 |
---|---|
1 | 张三 |
3 | 王五 |
2.3 去重查询
SELECT DISTINCT 课号
FROM 必修课;
列出所有必修课的课号:
课号 |
---|
101 |
102 |
3. 筛选数据 (WHERE)
3.1 基础条件查询
SELECT * FROM students WHERE age > 18;
3.2 多条件查询
-
求 1 号课成绩⼤于 80 分的学⽣的学号及成绩,并按成绩由⾼到低列出。
SELECT 学号, 成绩
FROM 选课
WHERE 课号 = '1' AND 成绩 > 80
ORDER BY 成绩 DESC;
假设 选课
表数据如下:
学号 | 课号 | 成绩 |
---|---|---|
1 | 1 | 85 |
2 | 1 | 75 |
3 | 1 | 90 |
4 | 2 | 88 |
5 | 1 | 95 |
查询结果
执行上述查询后,结果将是:
学号 | 成绩 |
---|---|
5 | 95 |
3 | 90 |
1 | 85 |
2.列出非软件专业学生的名单。
方法一:使用 <>
运算符
SELECT 姓名
FROM 学生
WHERE 专业 <> "软件";
方法二:使用 NOT
运算符
SELECT 姓名
FROM 学生
WHERE NOT 专业 = "软件";
方法三:使用 !=
运算符
SELECT 姓名
FROM 学生
WHERE 专业 != "软件";
示例数据
假设 学生
表数据如下:
学号 | 姓名 | 专业 |
---|---|---|
1 | 张三 | 软件 |
2 | 李四 | 网络 |
3 | 王五 | 软件 |
4 | 赵六 | 电子 |
查询结果
无论使用哪种方法,查询结果都将是:
姓名 |
---|
李四 |
赵六 |
1. 列出选修1号课或3号课的全体学生的学号和成绩
方法一 :使用 OR
运算符
SELECT 学号, 成绩
FROM 选课
WHERE 课号 = "1" OR 课号 = "3";
方法二 :使用 IN
运算符
SELECT 学号, 成绩
FROM 选课
WHERE 课号 IN ("1", "3");
2. 列出没有选修1号课和3号课的学生的学号和成绩
方法一 :使用 !=
和 AND
运算符
SELECT 学号, 成绩
FROM 选课
WHERE 课号 != "1" AND 课号 != "3";
方法二 :使用 NOT IN
运算符
SELECT 学号, 成绩
FROM 选课
WHERE 课号 NOT IN ("1", "3");
示例数据
假设 选课
表数据如下:
学号 | 课号 | 成绩 |
---|---|---|
1 | 1 | 85 |
2 | 2 | 75 |
3 | 1 | 90 |
4 | 3 | 88 |
5 | 2 | 95 |
查询结果
1. 列出选修1号课或3号课的全体学生的学号和成绩
无论使用哪种方法,查询结果都将是:
学号 | 成绩 |
---|---|
1 | 85 |
3 | 90 |
4 | 88 |
2. 列出没有选修1号课和3号课的学生的学号和成绩
无论使用哪种方法,查询结果都将是:
学号 | 成绩 |
---|---|
2 | 75 |
5 | 95 |
3.3 模糊查询
. 列出所有98级学生的学生成绩情况
方法一 :使用 LIKE "98%"
SELECT *
FROM 选课
WHERE 学号 LIKE "98%";
方法二 :使用 LIKE "98_"
SELECT *
FROM 选课
WHERE 学号 LIKE "98_";
2. 列出非98级学生的学生成绩情况
方法一 :使用 NOT LIKE "98%"
SELECT *
FROM 选课
WHERE 学号 NOT LIKE "98%";
方法二 :使用 NOT LIKE "98_"
SELECT *
FROM 选课
WHERE 学号 NOT LIKE "98_";
示例数据
假设 选课
表数据如下:
学号 | 课号 | 成绩 |
---|---|---|
98001 | 1 | 85 |
98002 | 1 | 75 |
99001 | 1 | 90 |
98003 | 2 | 88 |
99002 | 2 | 95 |
查询结果
1. 列出所有98级学生的学生成绩情况
-
方法一 (
LIKE "98%"
):学号 课号 成绩 98001 1 85 98002 1 75 98003 2 88 -
方法二 (
LIKE "98_"
):学号 课号 成绩 98001 1 85 98002 1 75 98003 2 88
2. 列出非98级学生的学生成绩情况
-
方法一 (
NOT LIKE "98%"
):学号 课号 成绩 99001 1 90 99002 2 95 -
方法二 (
NOT LIKE "98_"
):学号 课号 成绩 99001 1 90 99002 2 95
3.4 范围查询
1. 查询成绩在70到80分之间的选课记录
方法一 :使用 >=
和 <=
运算符
SELECT *
FROM 选课
WHERE 成绩 >= 70 AND 成绩 <= 80;
方法二 :使用 BETWEEN
运算符
SELECT *
FROM 选课
WHERE 成绩 BETWEEN 70 AND 80;
2. 查询不在70到80分范围内的选课记录
方法一 :使用 <=
和 >=
运算符
SELECT *
FROM 选课
WHERE 成绩 <= 70 OR 成绩 >= 80;
方法二 :使用 NOT BETWEEN
运算符
SELECT *
FROM 选课
WHERE 成绩 NOT BETWEEN 70 AND 80;
示例数据
假设 选课
表数据如下:
学号 | 课号 | 成绩 |
---|---|---|
1 | 1 | 65 |
2 | 1 | 75 |
3 | 1 | 85 |
4 | 2 | 70 |
5 | 2 | 80 |
查询结果
1. 查询成绩在70到80分之间的选课记录
无论使用哪种方法,查询结果都将是:
学号 | 课号 | 成绩 |
---|---|---|
2 | 1 | 75 |
4 | 2 | 70 |
5 | 2 | 80 |
2. 查询不在70到80分范围内的选课记录
无论使用哪种方法,查询结果都将是:
学号 | 课号 | 成绩 |
---|---|---|
1 | 1 | 65 |
3 | 1 | 85 |
4. 排序数据 (ORDER BY)
4.1 按成绩降序排列
SELECT * FROM students ORDER BY score DESC;
4.2 按年龄升序、成绩降序排列
SELECT * FROM students ORDER BY age ASC, score DESC;
5. 聚合查询 (GROUP BY + HAVING)
5.1 统计每个年龄段的学生人数
SELECT age, COUNT(*) AS student_count FROM students GROUP BY age;
5.2 计算不同性别的平均成绩
SELECT gender, AVG(score) AS avg_score FROM students GROUP BY gender;
5.3 统计学生数量大于2的年龄段
SELECT age, COUNT(*) AS student_count FROM students GROUP BY age HAVING COUNT(*) > 2;
6. 连接查询 (JOIN) 重要!!
6.1 连接查询的基本概念
- 连接查询:用于从多个表中提取数据,并通过相关列建立表之间的关联。
- 常用连接类型 :
- 内连接(INNER JOIN):只返回满足连接条件的记录。
- 外连接(LEFT JOIN, RIGHT JOIN, FULL JOIN):返回满足连接条件的记录以及不满足条件的部分记录。
- 自连接(SELF JOIN):将表与自身连接。
- 连接条件 :通过
ON
或WHERE
子句指定表之间的关联列。
6.2 内连接查询
知识点讲解
-
INNER JOIN
:默认的连接类型,返回满足连接条件的记录。 -
语法 :
SELECT 列1, 列2, ... FROM 表1 INNER JOIN 表2 ON 表1.列 = 表2.列;
-
等价写法 :在
WHERE
子句中指定连接条件(旧式写法)。
SQL 代码示例
-
列出选修1号课的学生姓名及成绩:
SELECT 姓名, 成绩 FROM 学生, 选课 WHERE 学生.学号 = 选课.学号 AND 课号 = '1';
等价写法:
SELECT 姓名, 成绩 FROM 学生 INNER JOIN 选课 ON 学生.学号 = 选课.学号 WHERE 课号 = '1';
-
列出选修1号课的学生的学号、姓名及成绩:
SELECT 学生.学号, 姓名, 成绩 FROM 学生, 选课 WHERE 学生.学号 = 选课.学号 AND 课号 = '1';
等价写法:
SELECT 学生.学号, 姓名, 成绩 FROM 学生 INNER JOIN 选课 ON 学生.学号 = 选课.学号 WHERE 课号 = '1';
3. 分组聚合查询
知识点讲解
GROUP BY
:用于对结果集进行分组,通常与聚合函数(如SUM
,COUNT
,AVG
等)一起使用。HAVING
:用于过滤分组后的结果集。SUM
函数:计算指定列的总和。
SQL 代码示例
-
求出总分大于150的学生的学号、姓名及总成绩 :
SELECT 学生.学号, 姓名, SUM(成绩) AS 总成绩 FROM 学生, 选课 WHERE 学生.学号 = 选课.学号 GROUP BY 选课.学号 HAVING SUM(成绩) > 150;
等价写法 :
SELECT 学生.学号, 姓名, SUM(成绩) AS 总成绩 FROM 学生 INNER JOIN 选课 ON 学生.学号 = 选课.学号 GROUP BY 选课.学号 HAVING SUM(成绩) > 150;
++为什么这里要用到GROUP BY?++
-
GROUP BY
的作用:- 将结果集按指定的列(或多个列)进行分组。
- 在本例中,按
选课.学号
分组,即对每个学生的选课记录进行分组。
-
SUM(成绩)
的作用:- 对每个分组中的
成绩
列进行求和。 - 如果没有
GROUP BY
,SUM(成绩)
会计算整个表的成绩
总和,而不是每个学生的总成绩。
- 对每个分组中的
-
HAVING
的作用:- 用于过滤分组后的结果集。
- 在本例中,筛选出总成绩大于 150 的学生。
-
为什么需要
GROUP BY
:- 如果不使用
GROUP BY
,查询会报错,因为SUM(成绩)
是一个聚合函数,而学生.学号
和姓名
是非聚合列,SQL 无法确定如何将这两者关联。 GROUP BY
明确指定了按选课.学号
分组,从而可以正确计算每个学生的总成绩。
- 如果不使用
示例数据
假设 学生
表数据如下:
学号 | 姓名 |
---|---|
1 | 张三 |
2 | 李四 |
3 | 王五 |
选课
表数据如下:
学号 | 课号 | 成绩 |
---|---|---|
1 | 1 | 80 |
1 | 2 | 90 |
2 | 1 | 70 |
2 | 2 | 60 |
3 | 1 | 85 |
3 | 2 | 95 |
查询结果
执行上述查询后,结果将是:
学号 | 姓名 | 总成绩 |
---|---|---|
1 | 张三 | 170 |
3 | 王五 | 180 |
- 学号 = 1 :
- 成绩:80 + 90 = 170。
- 总成绩大于 150,符合条件。
- 学号 = 2 :
- 成绩:70 + 60 = 130。
- 总成绩不大于 150,不符合条件。
- 学号 = 3 :
- 成绩:85 + 95 = 180。
- 总成绩大于 150,符合条件。
4. 连接查询的注意事项
-
明确连接条件:连接查询必须指定表之间的关联列,否则会产生笛卡尔积(Cartesian Product),导致结果集过大。
-
使用表别名 :当表名较长或查询涉及多个表时,可以使用表别名简化代码。
SELECT s.学号, s.姓名, c.成绩 FROM 学生 AS s INNER JOIN 选课 AS c ON s.学号 = c.学号 WHERE c.课号 = '1';
-
避免歧义列名 :如果多个表中有相同的列名,必须使用表名或别名限定列名,例如
学生.学号
。
5. 连接查询的综合应用
示例:查询每个学生的总成绩及平均成绩
SELECT 学生.学号, 姓名, SUM(成绩) AS 总成绩, AVG(成绩) AS 平均成绩
FROM 学生
INNER JOIN 选课 ON 学生.学号 = 选课.学号
GROUP BY 学生.学号, 姓名;
示例:查询选修了1号课和2号课的学生
SELECT 学生.学号, 姓名
FROM 学生
INNER JOIN 选课 AS c1 ON 学生.学号 = c1.学号 AND c1.课号 = '1'
INNER JOIN 选课 AS c2 ON 学生.学号 = c2.学号 AND c2.课号 = '2';
假设还有一个 courses
表,包括 course_id
(课程ID) 和 student_id
(学生ID)
6.3 自连接 (SELF JOIN)
1. 列出专业相同的学生姓名及专业信息
SELECT a.姓名, b.姓名, 专业
FROM 学生 a, 学生 b
WHERE a.学号 <> b.学号 AND a.专业 = b.专业;
知识点讲解
-
自连接(SELF JOIN):
- 将
学生
表与自身连接,生成两个实例a
和b
。 - 通过
a.学号 <> b.学号
确保排除同一个学生。 - 通过
a.专业 = b.专业
筛选出专业相同的学生。
- 将
-
查询逻辑:
- 从
学生
表中选取两个实例a
和b
。 - 筛选出学号不同但专业相同的学生。
- 返回这些学生的姓名及专业信息。
- 从
示例数据
假设 学生
表数据如下:
学号 | 姓名 | 专业 |
---|---|---|
1 | 张三 | 软件 |
2 | 李四 | 网络 |
3 | 王五 | 软件 |
4 | 赵六 | 电子 |
查询结果
姓名 | 姓名 | 专业 |
---|---|---|
张三 | 王五 | 软件 |
王五 | 张三 | 软件 |
2. 求至少选修1号课和2号课的学生的学号
SQL 查询语句
SELECT X.学号
FROM 选课 X, 选课 Y
WHERE X.学号 = Y.学号 AND X.课号 = "1" AND Y.课号 = "2";
知识点讲解
-
自连接(SELF JOIN):
- 将
选课
表与自身连接,生成两个实例X
和Y
。 - 通过
X.学号 = Y.学号
确保是同一个学生。 - 通过
X.课号 = "1"
和Y.课号 = "2"
筛选出同时选修1号课和2号课的学生。
- 将
-
查询逻辑:
- 从
选课
表中选取两个实例X
和Y
。 - 筛选出同一个学生(
X.学号 = Y.学号
),且选修了1号课(X.课号 = "1"
)和2号课(Y.课号 = "2"
)。 - 返回这些学生的学号。
- 从
示例数据
假设 选课
表数据如下:
学号 | 课号 | 成绩 |
---|---|---|
1 | 1 | 85 |
2 | 1 | 75 |
3 | 1 | 90 |
1 | 2 | 88 |
3 | 2 | 95 |
4 | 2 | 80 |
查询结果
学号 |
---|
1 |
3 |
6.2 左连接 (LEFT JOIN)
SELECT students.name, courses.course_name
FROM students
LEFT JOIN courses ON students.id = courses.student_id;
7.嵌套查询
7.1. 嵌套查询的基本概念
- 嵌套查询:在一个查询中嵌套另一个查询,通常用于解决复杂的查询需求。
- 子查询 :嵌套在查询中的查询,可以出现在
SELECT
、FROM
、WHERE
或HAVING
子句中。 - 常用运算符 :
IN
:用于匹配子查询的结果。EXISTS
:用于检查子查询是否返回结果。ANY
/ALL
:用于比较子查询的结果。
7.2 嵌套查询的示例
示例 1:列出选修汇编语言课的学生的学号
方法一 :使用 IN
子查询
SELECT 学号
FROM 选课
WHERE 课号 IN (SELECT 课号 FROM 课程 WHERE 课名 = "汇编语言");
方法二 :使用 EXISTS
子查询
SELECT 学号
FROM 选课
WHERE EXISTS (SELECT * FROM 课程 WHERE 课名 = "汇编语言" AND 选课.课号 = 课程.课号);
IN
子查询:- 子查询返回一个值列表,主查询筛选出匹配这些值的记录。
- 适用于子查询返回结果较少的情况。
EXISTS
子查询:- 子查询返回一个布尔值(
TRUE
或FALSE
),主查询根据布尔值筛选记录。 - 适用于子查询返回结果较多或需要关联主查询的情况。
- 子查询返回一个布尔值(
示例 2:求软件专业所有必修课的课程信息
方法一 :使用 IN
子查询
SELECT *
FROM 课程
WHERE 课号 IN (SELECT 课号 FROM 必修课 WHERE 必修专业 = "软件");
方法二 :使用 EXISTS
子查询
SELECT *
FROM 课程
WHERE EXISTS (SELECT * FROM 必修课 WHERE 必修专业 = "软件" AND 课程.课号 = 必修课.课号);
示例3:求选修2号课的学生中,成绩比选修1号课的最低成绩要高的学生的学号和成绩
方法一:使用子查询
SELECT 学号, 成绩
FROM 选课
WHERE 课号 = "2" AND 成绩 > (
SELECT MIN(成绩)
FROM 选课
WHERE 课号 = "1"
);
解题思路:
-
子查询 :获取选修1号课的最低成绩。
SELECT MIN(成绩) FROM 选课 WHERE 课号 = "1";
-
主查询 :筛选出选修2号课且成绩高于子查询结果的学生。
SELECT 学号, 成绩 FROM 选课 WHERE 课号 = "2" AND 成绩 > (子查询结果);
方法二:使用 ANY
关键字
SELECT 学号, 成绩
FROM 选课
WHERE 课号 = "2" AND 成绩 > ANY (
SELECT 成绩
FROM 选课
WHERE 课号 = "1"
);
解题思路:
-
子查询 :获取选修1号课的所有成绩。
SELECT 成绩 FROM 选课 WHERE 课号 = "1";
-
主查询 :筛选出选修2号课且成绩高于子查询中任意一个成绩的学生。
SELECT 学号, 成绩 FROM 选课 WHERE 课号 = "2" AND 成绩 > ANY (子查询结果);
示例4:求选修2号课的学生中,成绩比选修1号课的任何学生的成绩都要高的那些学生的学号和成绩
方法一:使用子查询
SELECT 学号, 成绩
FROM 选课
WHERE 课号 = "2" AND 成绩 > (
SELECT MAX(成绩)
FROM 选课
WHERE 课号 = "1"
);
解题思路:
-
子查询 :获取选修1号课的最高成绩。
SELECT MAX(成绩) FROM 选课 WHERE 课号 = "1";
-
主查询 :筛选出选修2号课且成绩高于子查询结果的学生。
SELECT 学号, 成绩 FROM 选课 WHERE 课号 = "2" AND 成绩 > (子查询结果);
方法二:使用 ALL
关键字
SELECT 学号, 成绩
FROM 选课
WHERE 课号 = "2" AND 成绩 > ALL (
SELECT 成绩
FROM 选课
WHERE 课号 = "1"
);
解题思路:
-
子查询 :获取选修1号课的所有成绩。
SELECT 成绩 FROM 选课 WHERE 课号 = "1";
-
主查询 :筛选出选修2号课且成绩高于子查询中所有成绩的学生。
SELECT 学号, 成绩 FROM 选课 WHERE 课号 = "2" AND 成绩 > ALL (子查询结果);
示例5 :列出每门课程中成绩最高的选课信息
SELECT *
FROM 选课 A
WHERE 成绩 = (
SELECT MAX(成绩)
FROM 选课 B
WHERE A.课号 = B.课号
);
知识点讲解
- 嵌套查询 :
- 在主查询中嵌套了一个子查询。
- 子查询的作用是找到每门课程的最高成绩。
- 子查询逻辑 :
SELECT MAX(成绩) FROM 选课 B WHERE A.课号 = B.课号
:- 从
选课
表(别名B
)中找到与主查询当前记录(A.课号
)相同的课程的最高成绩。
- 从
- 主查询逻辑 :
- 从
选课
表(别名A
)中筛选出成绩等于子查询结果的记录,即每门课程中成绩最高的选课信息。
- 从
示例6: 列出每个学生中成绩低于本人平均成绩的选课信息
SELECT *
FROM 选课 A
WHERE 成绩 < (
SELECT AVG(成绩)
FROM 选课 B
WHERE A.学号 = B.学号
);
知识点讲解
- 嵌套查询 :
- 在主查询中嵌套了一个子查询。
- 子查询的作用是计算每个学生的平均成绩。
- 子查询逻辑 :
SELECT AVG(成绩) FROM 选课 B WHERE A.学号 = B.学号
:- 从
选课
表(别名B
)中找到与主查询当前记录(A.学号
)相同的学生的平均成绩。
- 从
- 主查询逻辑 :
- 从
选课
表(别名A
)中筛选出成绩低于子查询结果的记录,即每个学生中成绩低于本人平均成绩的选课信息。
- 从
7.3. 嵌套查询的注意事项
-
子查询的结果:
- 子查询必须返回一个值或一组值,以便主查询使用。
- 例如:
IN
子查询必须返回一个值列表,EXISTS
子查询必须返回一个布尔值。
-
子查询的性能:
- 子查询可能会影响查询性能,尤其是在数据量较大时。
- 优化子查询的方法包括:
- 使用索引。
- 将子查询改写为连接查询。
-
子查询的嵌套深度:
- 子查询可以嵌套多层,但嵌套深度过深会增加查询复杂度,降低可读性。
总结
SELECT
语句是 SQL 语言中最重要的查询工具,通过 WHERE 条件筛选,ORDER BY 排序,GROUP BY 聚合,JOIN 连接以及子查询等方式,可以高效地查询和分析数据。通过本文系统地练习,可以打定深厚的 SQL 学习基础。
综合练习主页接