第11章 Select语句
11.1 SELECT语句概述
11.1.1 什么是SELECT语句
SELECT语句是SQL中用于从数据库表中检索数据的最基本、最常用的语句。它允许用户根据指定的条件从一个或多个表中查询数据,并以指定的格式返回结果集。
11.1.2 SELECT语句的作用
- 从表中检索数据
- 筛选满足条件的数据
- 对数据进行排序和分组
- 对数据进行计算和汇总
- 连接多个表的数据
- 执行子查询和复杂查询
11.1.3 SELECT语句的执行顺序
SELECT语句的逻辑执行顺序与语法顺序有所不同:
1. FROM - 确定要查询的表
2. WHERE - 过滤行数据
3. GROUP BY - 分组数据
4. HAVING - 过滤分组结果
5. SELECT - 选择要显示的列
6. ORDER BY - 排序结果集
7. LIMIT - 限制返回行数
11.2 SELECT语句基本语法
11.2.1 基本SELECT语法
11.2.2 选择所有列
使用通配符
*可以选择表中的所有列:11.2.3 选择特定列
指定要查询的列名,用逗号分隔:
11.2.4 使用列别名
为查询结果的列指定别名,使用
AS关键字(可省略):11.2.5 消除重复行
使用
DISTINCT关键字消除查询结果中的重复行:11.3 WHERE子句过滤数据
11.3.1 WHERE子句的作用
WHERE子句用于过滤表中的行,只返回满足条件的行。
11.3.2 比较运算符
运算符 | 描述 | 示例 |
= | 等于 | WHERE age = 18 |
<> 或 != | 不等于 | WHERE gender <> ‘男’ |
> | 大于 | WHERE salary > 5000 |
< | 小于 | WHERE score < 60 |
>= | 大于等于 | WHERE age >= 18 |
<= | 小于等于 | WHERE price <= 100 |
11.3.3 逻辑运算符
运算符 | 描述 | 示例 |
AND | 逻辑与,同时满足多个条件 | WHERE age >= 18 AND gender = ‘男’ |
OR | 逻辑或,满足任意一个条件 | WHERE department = ‘销售’ OR salary > 8000 |
NOT | 逻辑非,取反条件 | WHERE NOT age < 18 |
11.3.4 范围查询
- BETWEEN…AND:查询指定范围内的值
- IN:查询列值在指定集合中的行
11.3.5 模糊查询
使用LIKE关键字进行模糊查询,配合通配符:
-
%:匹配任意长度的字符串(包括空字符串)
- _:匹配单个字符11.3.6 NULL值查询
使用IS NULL或IS NOT NULL查询NULL值:
11.4 ORDER BY排序结果
11.4.1 ORDER BY的作用
ORDER BY用于对查询结果进行排序。
11.4.2 基本排序
11.4.3 多列排序
11.4.4 使用别名排序
11.5 LIMIT限制返回行数
11.5.1 LIMIT的作用
LIMIT用于限制查询结果返回的行数,常用于分页查询。
11.5.2 基本用法
11.5.3 分页查询示例
11.6 聚合函数
11.6.1 什么是聚合函数
聚合函数用于对一组值进行计算并返回单个值,常用于统计分析。
11.6.2 常用聚合函数
函数 | 描述 | 示例 |
COUNT() | 计算行数 | COUNT(*), COUNT(列名) |
SUM() | 计算数值列的总和 | SUM(salary) |
AVG() | 计算数值列的平均值 | AVG(score) |
MAX() | 求列的最大值 | MAX(age) |
MIN() | 求列的最小值 | MIN(price) |
11.6.3 COUNT()函数的使用
11.6.4 其他聚合函数示例
11.7 GROUP BY分组
11.7.1 GROUP BY的作用
GROUP BY用于将数据分组,以便对每组数据应用聚合函数。
11.7.2 基本分组
11.7.3 多列分组
11.7.4 HAVING过滤分组结果
HAVING用于过滤分组后的结果,类似于WHERE,但HAVING用于分组,WHERE用于行。
11.7.5 WHERE和HAVING的区别
特性 | WHERE | HAVING |
作用对象 | 行 | 分组 |
执行顺序 | 在GROUP BY之前 | 在GROUP BY之后 |
可使用聚合函数 | 否 | 是 |
可使用列别名 | 否 | 是(部分数据库) |
11.8 连接查询
11.8.1 连接查询的概念
连接查询用于从两个或多个表中获取相关数据,通过表之间的关联关系(通常是外键)将它们连接起来。
11.8.2 内连接(INNER JOIN)
内连接返回两个表中匹配的行,即只返回满足连接条件的行。
11.8.3 左连接(LEFT JOIN)
左连接返回左表中的所有行,以及右表中匹配的行。如果右表中没有匹配的行,则返回NULL。
11.8.4 右连接(RIGHT JOIN)
右连接返回右表中的所有行,以及左表中匹配的行。如果左表中没有匹配的行,则返回NULL。
11.8.5 全连接(FULL JOIN)
全连接返回左表和右表中的所有行。如果没有匹配的行,则返回NULL。
11.8.6 自连接
自连接是指同一个表内部的连接,用于处理表中存在的层次关系或自引用关系。
11.9 子查询
11.9.1 子查询的概念
子查询是嵌套在另一个查询中的查询,也称为内部查询。外部查询使用子查询的结果。
11.9.2 子查询的位置
子查询可以出现在:
- WHERE子句中
- FROM子句中
- SELECT子句中
- HAVING子句中
11.9.3 WHERE子句中的子查询
11.9.4 FROM子句中的子查询
FROM子句中的子查询被当作临时表使用,称为派生表,需要指定别名。
11.9.5 SELECT子句中的子查询
11.9.6 相关子查询与非相关子查询
- 非相关子查询:子查询可以独立执行,不依赖外部查询
- 相关子查询:子查询依赖外部查询的结果,需要逐行执行
11.9.7 EXISTS和NOT EXISTS
EXISTS用于检查子查询是否返回结果,返回布尔值。
11.10 集合运算
11.10.1 集合运算的概念
集合运算用于合并两个或多个查询的结果集,包括UNION、INTERSECT和EXCEPT。
11.10.2 UNION(并集)
UNION用于合并两个查询的结果集,并自动消除重复行。
11.10.3 UNION ALL(包含重复行的并集)
UNION ALL合并两个查询的结果集,保留重复行。
11.10.4 INTERSECT(交集)
INTERSECT返回两个查询结果集的交集,即同时存在于两个结果集中的行。
11.10.5 EXCEPT(差集)
EXCEPT返回第一个查询结果集中存在但第二个查询结果集中不存在的行。
11.10.6 集合运算的规则
- 参与运算的两个查询结果集必须具有相同的列数
- 对应列的数据类型必须兼容
- 可以使用ORDER BY对最终结果进行排序
11.11 SELECT语句最佳实践
11.11.1 性能优化
- 只选择需要的列,避免使用
SELECT *
- 合理使用索引
- 尽量减少子查询的嵌套层次
- 合理使用连接类型
- 避免在WHERE子句中对列进行函数操作
- 合理设置LIMIT,避免返回大量数据
11.11.2 可读性优化
- 使用大写关键字,小写表名和列名
- 适当缩进和换行
- 使用别名使查询结果更易理解
- 添加注释(如果查询复杂)
11.11.3 安全性考虑
- 避免SQL注入攻击,使用参数化查询
- 限制查询返回的数据量
- 对敏感数据进行脱敏处理
11.12 综合示例
11.12.1 示例1:学生成绩管理
假设有以下表结构:
- students(id, name, class_id, gender, age)
- classes(id, class_name)
- scores(student_id, subject, score)
11.12.2 示例2:员工管理系统
假设有以下表结构:
- employees(id, name, department_id, manager_id, salary, hire_date)
- departments(id, department_name)
11.13 常见问题与解决方案
11.13.1 问题1:查询结果中出现重复行
- 解决方案:使用DISTINCT关键字或检查连接条件是否正确
11.13.2 问题2:查询速度慢
- 解决方案:优化查询语句,添加适当的索引,避免全表扫描
11.13.3 问题3:连接查询返回NULL值
- 解决方案:理解不同连接类型的区别,根据需求选择合适的连接类型
11.13.4 问题4:聚合函数返回错误结果
- 解决方案:检查GROUP BY子句是否正确,确保非聚合列都在GROUP BY中
11.13.5 问题5:子查询执行效率低
- 解决方案:考虑使用连接查询替代子查询,或优化子查询的条件
11.14 小结
SELECT语句是SQL中最常用、最重要的语句之一,用于从数据库中检索数据。本章介绍了SELECT语句的基本语法、过滤数据、排序结果、分组统计、连接查询、子查询和集合运算等内容。通过学习这些知识,您可以编写各种复杂的查询语句,从数据库中获取所需的数据。
在实际应用中,需要根据具体需求选择合适的查询方式,并注意查询的性能和可读性。同时,还需要注意SQL注入等安全问题,确保数据库的安全性。
11.15 练习题
- 编写SQL语句,查询students表中所有姓名、年龄和性别。
- 编写SQL语句,查询students表中年龄大于18岁的男生,按年龄降序排序。
- 编写SQL语句,查询students表中不同性别的学生人数。
- 编写SQL语句,查询students表中姓名包含”明”的学生,按姓名升序排序。
- 编写SQL语句,查询students表中数学成绩大于90且语文成绩大于85的学生姓名和班级。
- 编写SQL语句,查询每个班级的平均数学成绩,只显示平均成绩大于80的班级。
- 编写SQL语句,查询所有学生的姓名、班级名称和各科成绩。
- 编写SQL语句,查询工资高于部门平均工资的员工姓名、部门和工资。
- 编写SQL语句,查询至少有3名员工的部门名称和员工人数。
- 编写SQL语句,查询没有学生的班级名称。
