乐途乐途
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
  • 学习路径
  • 第1章 数据库基础与安装

    • MySQL 简介
    • MySQL 5.6 到 5.7 到 8.0 关键差异速查
    • 安装 MySQL 5.7
    • 连接与断开服务器
    • 创建数据库
    • 创建数据表
    • 数据库与数据表
    • 加载数据
    • 获取数据库信息
    • 批处理模式
    • SHOW 语句汇总
    • FLUSH 与 RESET 语句
    • my.cnf 核心参数
    • 字符集与排序规则
  • 第2章 SQL基础查询

    • SELECT
    • WHERE
    • ORDER BY
    • LIMIT
    • COUNT
    • 聚合函数
    • 比较运算符
    • 逻辑运算符
    • 算术运算符
    • 模式匹配
    • NULL 值处理
    • UPDATE
    • DELETE
    • REPLACE
    • SELECT INTO
  • 第3章 数据类型与运算符

    • 数值类型
    • 字符串类型
    • 日期时间类型
    • BIT 类型
    • ENUM 类型
    • SET 类型
    • JSON 类型
    • 类型转换
  • 第4章 函数与表达式

    • 字符串函数
    • 数值函数
    • 日期函数
    • 全文检索函数
  • 第5章 高级查询与子查询

    • JOIN
    • 子查询
    • UNION
    • GROUP BY
    • HAVING
    • DISTINCT
  • 第6章 表与索引

    • 数据定义语言
    • 修改表结构
    • 视图
    • 修改视图与检查选项
    • 外键
    • 索引
    • 唯一索引
    • 复合索引
    • 存储引擎对比
    • 分区表
    • 第一范式与第二范式
    • 第三范式与 BC 范式
    • 反范式设计
  • 第7章 存储过程与函数

    • 存储过程
    • 存储函数
    • 变量
    • 流程控制
    • 游标
    • 预处理语句
  • 第8章 事务与锁

    • 事务
    • 事务隔离级别
    • 锁机制
    • MVCC
    • 死锁专题分析
    • LOCK TABLES
    • XA 事务
  • 第9章 用户管理与安全

    • 用户管理
    • 权限管理
    • 角色
    • SQL 注入防范
  • 第10章 性能优化入门

    • 执行计划
    • 索引优化
    • 查询优化
    • 查询优化器提示
    • 慢查询日志
    • InnoDB 深入机制
    • InnoDB 专项优化
    • Performance Schema
    • sys Schema
  • 第11章 复制与高可用

    • 主从复制原理
    • 半同步复制配置
    • binlog 开启与 point-in-time 恢复
    • mysqldump 全库备份
    • mysqldump 单表与条件备份
    • mysqldump 恢复与导入
    • xtrabackup 全量热备
    • xtrabackup 准备与恢复
    • xtrabackup 增量与流式备份
  • 第12章 触发器与事件

    • 触发器
    • 事件调度器
  • 参考

    • MySQL 5.7 专业术语大全
    • MySQL 5.7 关键字与保留字大全

SELECT

导学

SELECT 是 SQL 中使用频率最高的语句,也是你"从数据库中获取数据"的唯一途径。本节从最简单的全表查询开始,逐步拆解 SELECT 的核心语法结构。

定义

SELECT:DQL(数据查询语言)语句,用于从一个或多个表中检索数据。它指定了要返回的列、数据来源、筛选条件、排序方式和结果限制。

核心语法

SELECT [DISTINCT] 列1, 列2, ...
FROM 表名
[WHERE 条件]
[ORDER BY 列 [ASC|DESC]]
[LIMIT 数量];

演示数据准备

为了让你看到每一步的真实效果,我们先建立一张员工表并插入数据。

DROP TABLE IF EXISTS employees;

CREATE TABLE employees (
    emp_id INT PRIMARY KEY AUTO_INCREMENT,
    emp_name VARCHAR(20),
    dept VARCHAR(20),
    score DECIMAL(5,2)
);

INSERT INTO employees (emp_name, dept, score) VALUES
('大翔', '技术部', 100),
('白歌', '技术部', NULL);

当前 employees 表中的完整数据如下:

emp_idemp_namedeptscore
1大翔技术部100
2白歌技术部NULL

SQL 示例

场景一:查询所有列(开发调试用,生产慎用)

当前数据状态:见上文 employees 表完整数据。

执行语句:

SELECT * FROM employees;

操作后结果:

emp_idemp_namedeptscore
1大翔技术部100
2白歌技术部NULL

结果解读:* 是通配符,表示返回所有列。在开发阶段方便快速查看数据,但在生产环境的应用程序代码中应明确指定列名,原因有三:

  1. 减少网络传输(多余的列浪费带宽)
  2. 避免表结构变更导致程序出错
  3. 利用覆盖索引优化查询(后续章节详解)

场景二:查询指定列(推荐)

当前数据状态:见上文 employees 表完整数据。

执行语句:

SELECT emp_name, dept, score FROM employees;

操作后结果:

emp_namedeptscore
大翔技术部100
白歌技术部NULL

结果解读:只返回 emp_name、dept、score 三列,数据量更小,接口更稳定。即使表后面新增了列,这条查询的返回结构也不会改变。

场景三:给列起别名(增强可读性)

当前数据状态:见上文 employees 表完整数据。

执行语句:

SELECT
    emp_name AS 姓名,
    dept AS 部门,
    score AS 绩效分
FROM employees;

操作后结果:

姓名部门绩效分
大翔技术部100
白歌技术部NULL

结果解读:AS 关键字可以省略,但建议保留以增强可读性。别名在结果集中显示为列标题,不影响原始列名。注意:WHERE 子句中不能使用别名,因为 SQL 执行顺序中 WHERE 在 SELECT 之前。

场景四:去重查询

当前数据状态:见上文 employees 表完整数据,其中 dept 列有重复值。

执行语句:

SELECT DISTINCT dept FROM employees;

操作后结果:

dept
技术部

结果解读:DISTINCT 对 dept 列去重,只保留不同的部门名称。当前表中所有员工都在技术部,去重后只有 1 行。注意:DISTINCT 不是函数,它作用于所有列的组合。如果写成 SELECT DISTINCT dept, score,则表示"部门+绩效分"的组合去重,结果可能更多。

再看一个多列去重的例子:

SELECT DISTINCT dept, score FROM employees;

操作后结果:

deptscore
技术部100
技术部NULL

结果解读:(技术部, 100)、(技术部, NULL) 被视为不同的组合,因此都保留。这说明 DISTINCT 是对整行选定列的组合去重,而非单独对某一列去重。

场景五:常量表达式与计算

当前数据状态:见上文 employees 表完整数据。

执行语句:

SELECT
    emp_name,
    CONCAT(dept, '-精英') AS dept_label,
    score * 0.4 + 60 AS adjusted_score
FROM employees;

操作后结果:

emp_namedept_labeladjusted_score
大翔技术部-精英100.0000
白歌技术部-精英NULL

结果解读:SELECT 不仅可以选列,还可以写表达式。数据库在返回结果前会计算这些表达式。注意白歌的 adjusted_score 为 NULL,因为 score 为 NULL,任何包含 NULL 的算术运算结果都是 NULL。

场景六:无 FROM 的 SELECT(常量计算)

当前数据状态:无需表数据,直接计算常量表达式。

执行语句:

SELECT 1 + 1;
SELECT VERSION();
SELECT NOW();
SELECT UPPER('hello mysql');

操作后结果:

SELECT 1 + 1;

1 + 1
2

SELECT VERSION();

VERSION()
5.7.xxx

SELECT NOW();

NOW()
2026-06-10 15:58:44

SELECT UPPER('hello mysql');

UPPER('hello mysql')
HELLO MYSQL

结果解读:MySQL 允许无 FROM 子句的 SELECT,常用于计算常量表达式、获取系统信息或测试连接。这在验证函数行为和调试时非常有用。

SELECT 执行顺序(重要)

关键认知:虽然书写顺序是 SELECT ... FROM ... WHERE ...,但执行顺序是 FROM → WHERE → GROUP BY → HAVING → SELECT → DISTINCT → ORDER BY → LIMIT。理解这个顺序对写复杂查询和排查错误至关重要。

我们用一张小表验证执行顺序中 WHERE 先于 SELECT:

-- 建表
CREATE TABLE IF NOT EXISTS test_order (
    id INT,
    val INT
);
INSERT INTO test_order VALUES (1, 10), (2, 20), (3, 30);

当前数据状态:

idval
110
220
330

执行语句:

-- 错误:WHERE 中不能用 SELECT 中定义的别名
SELECT id, val * 2 AS double_val FROM test_order WHERE double_val > 30;

MySQL 会报错:Unknown column 'double_val' in 'where clause'。

正确写法:

SELECT id, val * 2 AS double_val FROM test_order WHERE val * 2 > 30;

操作后结果:

iddouble_val
240
360

结果解读:WHERE 在 SELECT 之前执行,此时 double_val 这个别名还不存在,所以 WHERE 中只能使用原始列名或表达式。而 ORDER BY 在 SELECT 之后执行,因此可以使用别名。

常见误区

误区正解
"SELECT * 最方便,Always 用"生产代码应明确列名,* 仅用于临时查询。
"DISTINCT 是函数,可以 DISTINCT(dept)"DISTINCT 是关键字而非函数,正确写法是 SELECT DISTINCT dept。
"别名可以在 WHERE 中使用"不行。WHERE 执行在 SELECT 之前,此时别名还未生成。
"DISTINCT 只对后面第一个列生效"DISTINCT 作用于所有选定列的组合。

面试考点

Q:为什么生产环境不推荐 SELECT *?

  1. 增加网络开销;2. 表结构变更可能导致程序字段映射错误;3. 无法利用覆盖索引(查询的列全在索引中时,无需回表查数据行)。

Q:SELECT 语句中别名可以在哪些地方使用?

别名在 SELECT 执行后才生效,因此只能用于 ORDER BY、HAVING 和外部查询,不能用于 WHERE、GROUP BY。

Q:SELECT 1+1 不跟 FROM 可以吗?

可以。MySQL 允许无 FROM 子句的 SELECT,常用于计算常量表达式或测试连接,如 SELECT VERSION(), NOW();。

Q:DISTINCT 和 GROUP BY 去重有什么区别?

DISTINCT 只是去重,不聚合;GROUP BY 会把相同值的行归为一组,通常配合聚合函数使用。在 MySQL 5.7 中,单纯去重时两者结果相同,但 DISTINCT 语义更清晰。

小结

  • SELECT 是数据查询的核心语句
  • 生产环境应明确指定列名,避免使用 *
  • 理解 SQL 的执行顺序(FROM → WHERE → SELECT → ORDER BY → LIMIT)是写好复杂查询的基础
  • DISTINCT 实现去重,作用于所有选定列的组合
  • 别名只能在 ORDER BY、HAVING 中使用,不能在 WHERE、GROUP BY 中使用

下一章引子:学会了选列,下一步是学会筛选——只拿你想要的那部分行。

下一页
WHERE