首页 / MySQL 入门教程 / 基础查询 SELECT 与 DISTINCT

MySQL 入门教程

基础查询 SELECT 与 DISTINCT

本教程共 46 篇 · 第 19 篇 · 更新于 2026-07-30 · 约 9 分钟阅读

MySQLMySQL 入门教程SELECTDISTINCTSQL 查询别名DQL

19. 基础查询 SELECT 与 DISTINCT

本节目标:学会用 SELECT 从表里取数据,掌握查全部列、查指定列、用 DISTINCT 去重、给表和列起别名,理解 SELECT * 什么时候能用什么时候不能碰。

19.1 SELECT 是干什么的

前面几章学了怎么插数据、改数据、删数据。现在到了最核心的部分—查数据。

SELECT 是 SQL 里用得最多的语句,没有之一。你日常工作中 80% 的 SQL 都是 SELECT。说白了,它就是”从表里把我要的数据捞出来”。

最简单的查询,查整张表所有数据:

SELECT * FROM users;

* 代表所有列。执行后,users 表里的全部行、全部列都显示出来:

+----+----------+----------------------+-----+---------------------+
| id | username | email                | age | created_at          |
+----+----------+----------------------+-----+---------------------+
|  1 | 张三     | zhangsan@example.com |  25 | 2026-07-30 10:00:00 |
|  2 | 李四     | lisi@example.com     |  30 | 2026-07-30 11:00:00 |
|  3 | 王五     | wangwu@example.com   |  28 | 2026-07-30 12:00:00 |
+----+----------+----------------------+-----+---------------------+
3 rows in set (0.00 sec)

19.2 查指定列

SELECT * 虽然方便,但实际开发中不推荐用。原因后面讲。更推荐的做法是指定要查的列:

SELECT username, age FROM users;

只查用户名和年龄两列:

+----------+-----+
| username | age |
+----------+-----+
| 张三     |  25 |
| 李四     |  30 |
| 王五     |  28 |
+----------+-----+

列的顺序由你决定,不必跟建表时的顺序一样:

SELECT age, username FROM users;

这样 age 在前,username 在后。

Tip

指定列查询不仅结果更清晰,速度也更快。数据库不需要读取不需要的列,网络传输的数据量也少。养成习惯:查什么列就写什么列,别偷懒用 *

19.3 SELECT * 的利弊

SELECT * 查所有列,看起来省事,但有几个问题:

问题说明
性能浪费查了一堆不需要的列,白白消耗 IO 和网络带宽
表结构变了就出事加了新列后,SELECT * 返回的列数变了,依赖列顺序的代码会崩
索引失效有些查询本可以走覆盖索引(只查索引列就够),SELECT * 强制回表
传输膨胀TEXT/BLOB 大字段被查出来,严重拖慢查询

什么时候可以用 SELECT *

  • 在命令行里快速看一眼表数据
  • 写临时脚本快速验证
  • 表只有两三列且数据量很小
Warning

生产代码里、API 接口里、视图定义里,不要用 SELECT *。我之前接手过一个项目,接口返回 SELECT *,后来表加了个 BLOB 字段存头像,接口响应时间从 50ms 涨到 2 秒。

19.4 DISTINCT:去掉重复行

查询结果里如果有重复的行,可以用 DISTINCT 去重。

比如想看看 users 表里都有哪些不同的年龄:

SELECT DISTINCT age FROM users;

不加 DISTINCT 的结果可能有重复(多个用户同岁),加了之后每种年龄只出现一次。

多列去重

DISTINCT 后面可以跟多列,去重的是这些列的组合:

SELECT DISTINCT age, username FROM users;

只有 age 和 username 都完全相同的行才算重复,才会被去掉。

Note

DISTINCT 是对整行结果去重,不是对某一列去重。它作用于 SELECT 后面所有列的组合。如果你只想对一列去重但又要显示其他列,那需要用 GROUP BY,后面章节会讲。

DISTINCT 的性能

DISTINCT 需要对结果排序去重,数据量大时有性能开销。MySQL 内部通常用临时表来处理去重。

如果列上有索引,去重会快一些,因为索引本身就是有序的。

-- 如果 email 上有索引,这个去重会走索引,比较快
SELECT DISTINCT email FROM users;
Tip

| 如果只是想知道某列有多少个不同的值,用 COUNT(DISTINCT 列名) 比先 DISTINCT 再 COUNT 更高效。这在聚合函数章节会讲。

19.5 列别名(AS)

查出来的列名默认就是表里的字段名。但有时候你想给列起个更好看或更有意义的名字,用 AS 关键字:

SELECT username AS 用户名, age AS 年龄 FROM users;

结果就变成:

+--------+--------+
| 用户名 | 年龄   |
+--------+--------+
| 张三   |  25    |
| 李四   |  30    |
| 王五   |  28    |
+--------+--------+

AS 可以省略,效果一样:

SELECT username 用户名, age 年龄 FROM users;

但建议写上 AS,可读性更好。

别名在以下场景特别有用:

  • 计算列没有名字,需要起一个
  • 列名太长或不够直观
  • 多表连接时有同名列需要区分
-- 计算列起别名
SELECT username, amount * 0.9 AS 折后金额 FROM orders;

-- 函数结果起别名
SELECT username, UPPER(email) AS 大写邮箱 FROM users;
Warning

别名只在结果集中有效,不能在 WHERE 子句里用。因为 SQL 执行时 WHERE 比 SELECT 先执行,那时候别名还没生成。这个执行顺序后面会反复提到。

19.6 表别名

除了给列起别名,还能给表起别名。在多表查询时特别有用,能省很多字:

SELECT u.username, u.age
FROM users AS u
WHERE u.age > 25;

users AS u 给 users 表起了个短名 u,后面引用列时写 u.username 就行。

AS 同样可以省略:

SELECT u.username, u.age
FROM users u
WHERE u.age > 25;
Tip

多表查询时一定要用表别名,不然每列都要写完整的 表名.列名,SQL 会又长又难读。别名要短且有意义,比如 users 用 u、orders 用 o。

19.7 查询中的表达式和函数

SELECT 不只能查列,还能写表达式和调用函数:

-- 算术运算
SELECT username, age, age * 365 AS 出生天数 FROM users;

-- 字符串函数
SELECT username, CONCAT(username, '@example.com') AS 推测邮箱 FROM users;

-- 日期函数
SELECT username, YEAR(created_at) AS 注册年份 FROM users;

-- 条件表达式
SELECT username,
       CASE WHEN age >= 30 THEN '资深'
            WHEN age >= 25 THEN '中级'
            ELSE '新人'
       END AS 级别
FROM users;

这些在后面的函数章节会详细讲。这里只要知道:SELECT 后面能放的东西很灵活,不限于列名。

19.8 SELECT 的执行顺序

虽然 SQL 是先写 SELECT 后写 FROM,但 MySQL 执行时的顺序不是这样的:

1. FROM      -- 先确定从哪张表取数据
2. WHERE     -- 过滤行
3. GROUP BY  -- 分组
4. HAVING    -- 过滤分组
5. SELECT    -- 选择列、计算表达式
6. ORDER BY  -- 排序
7. LIMIT     -- 截取行数

理解这个顺序很重要。比如为什么 WHERE 里不能用列别名?因为 WHERE 在 SELECT 之前执行,别名还没生成。而 ORDER BY 在 SELECT 之后,所以 ORDER BY 里可以用别名。

-- 这个会报错:WHERE 里不能用别名
SELECT age * 365 AS 出生天数 FROM users WHERE 出生天数 > 9000;

-- 这个没问题:ORDER BY 里可以用别名
SELECT age * 365 AS 出生天数 FROM users ORDER BY 出生天数 DESC;
Note

记住这个执行顺序,后面学 WHERE、GROUP BY、ORDER BY 时都会用到。很多 SQL 报错就是因为不理解执行顺序,在不该用的地方用了别名或聚合函数。

19.9 小结

SELECT 是查询的起点。核心知识点:指定列查询优于 SELECT *、DISTINCT 去重作用于所有列的组合、AS 给列和表起别名让结果更清晰、理解 SELECT 的执行顺序能帮你避免很多坑。下一章我们给查询加上条件,学 WHERE 和运算符。