ORDER BY
导学
数据在表中的物理存储顺序是不可预测的。如果你需要按绩效分高低、姓名字母顺序来展示结果,就必须使用 ORDER BY。
定义
ORDER BY:对查询结果集按指定列进行排序。默认升序(ASC),可显式指定降序(DESC)。支持多列排序,按列的顺序依次比较。
核心语法
SELECT 列 FROM 表
ORDER BY 列1 [ASC|DESC], 列2 [ASC|DESC], ...;
演示数据准备
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_id | emp_name | dept | score |
|---|---|---|---|
| 1 | 大翔 | 技术部 | 100 |
| 2 | 白歌 | 技术部 | NULL |
SQL 示例
场景一:单列升序排序(默认)
当前数据状态:见上文 employees 表完整数据。
执行语句:
SELECT emp_name, emp_id FROM employees
ORDER BY emp_id;
-- 等价于
-- ORDER BY emp_id ASC;
操作后结果:
| emp_name | emp_id |
|---|---|
| 大翔 | 1 |
| 白歌 | 2 |
结果解读:按 emp_id 从小到大升序排列。不指定 ASC 或 DESC 时,默认是 ASC(升序)。
场景二:单列降序排序
当前数据状态:见上文 employees 表完整数据。
执行语句:
SELECT emp_name, score FROM employees
ORDER BY score DESC;
操作后结果:
| emp_name | score |
|---|---|
| 大翔 | 100 |
| 白歌 | NULL |
结果解读:按 score 从高到低降序排列。注意 NULL 在降序时排在最后面(MySQL 5.7 默认行为)。
场景三:多列排序
当前数据状态:见上文 employees 表完整数据。
执行语句:
SELECT dept, emp_name, score FROM employees
ORDER BY dept ASC, score DESC;
操作后结果:
| dept | emp_name | score |
|---|---|---|
| 技术部 | 大翔 | 100 |
| 技术部 | 白歌 | NULL |
结果解读:先按 dept 升序排列,同一部门内再按 score 降序排列。当前表中所有员工都在技术部。
场景四:按表达式排序
当前数据状态:见上文 employees 表完整数据。
执行语句:
SELECT emp_name, dept FROM employees
ORDER BY dept = '技术部' DESC, emp_id ASC;
操作后结果:
| emp_name | dept |
|---|---|
| 大翔 | 技术部 |
| 白歌 | 技术部 |
结果解读:ORDER BY 支持表达式和函数。这里 dept = '技术部' 返回 1(技术部)或 0(其他部门),按该表达式降序排序后,技术部的员工排在最前面;同值时再按 emp_id 升序排列。当前表中所有员工都在技术部。
场景五:按 SELECT 别名排序(合法)
当前数据状态:见上文 employees 表完整数据。
执行语句:
SELECT
emp_name,
IFNULL(score, 0) AS effective_score
FROM employees
ORDER BY effective_score DESC;
操作后结果:
| emp_name | effective_score |
|---|---|
| 大翔 | 100 |
| 白歌 | 0 |
结果解读:虽然 WHERE 中不能用别名,但 ORDER BY 可以,因为 ORDER BY 在 SELECT 之后执行。此时别名 effective_score 已经生成,可以直接使用。当前表中只有大翔有有效绩效分。
场景六:指定字段位置排序(不推荐)
当前数据状态:见上文 employees 表完整数据。
执行语句:
SELECT emp_name, score FROM employees
ORDER BY 2 DESC;
操作后结果:
| emp_name | score |
|---|---|
| 大翔 | 100 |
| 白歌 | NULL |
结果解读:ORDER BY 2 表示按 SELECT 列表中的第 2 个列(即 score)降序排序。这种写法虽然合法,但可读性差且脆弱——一旦 SELECT 列顺序改变,排序逻辑就会出错。生产环境应使用列名。
场景七:NULL 的排序控制
MySQL 5.7 中,ORDER BY 对 NULL 的默认处理规则:
- 升序(
ASC):NULL排在最前面 - 降序(
DESC):NULL排在最后面
我们用 score 列验证(白歌的 score 为 NULL):
执行语句(升序,NULL 在前):
SELECT emp_name, score FROM employees ORDER BY score ASC;
操作后结果:
| emp_name | score |
|---|---|
| 白歌 | NULL |
| 大翔 | 100 |
结果解读:NULL 默认排在升序的最前面。
如需自定义 NULL 的位置,将 NULL 排在最后(升序时):
SELECT emp_name, score FROM employees
ORDER BY score IS NULL, score ASC;
操作后结果:
| emp_name | score |
|---|---|
| 大翔 | 100 |
| 白歌 | NULL |
结果解读:score IS NULL 返回 1(NULL)或 0(非 NULL),先按此排序,非 NULL(0)在前,NULL(1)在后,再按实际 score 值排序。这样 NULL 就被排到了最后。
常见误区
| 误区 | 正解 |
|---|---|
| "不指定 ORDER BY 结果也有顺序" | 没有 ORDER BY 的结果集顺序是未定义的,可能因索引、执行计划变化而不同。 |
ORDER BY 可以用在 WHERE 中 | ORDER BY 是结果集排序,不能用于 WHERE。 |
ORDER BY RAND() 随机排序很快 | ORDER BY RAND() 需要为每行生成随机数并全排序,大数据量时极慢。 |
| "多列排序时第二个列没用" | 第二个列在第一个列值相同时才生效,是非常常用的功能。 |
面试考点
Q:ORDER BY 在 SQL 执行顺序中的位置?
ORDER BY在SELECT之后、LIMIT之前执行。因此它可以使用SELECT中定义的别名。
Q:大数据量排序慢怎么办?
- 确保
ORDER BY的列上有索引;2. 如果只需要 Top N,配合LIMIT可减少排序数据量;3. 避免对大量数据进行无索引排序。
Q:如何实现"将 NULL 值排在最后"?
ORDER BY column IS NULL, column ASC。column IS NULL返回 1(NULL)或 0(非 NULL),先按此排序,非 NULL 在前,再按实际值排序。
Q:ORDER BY 可以用函数吗?
可以,如
ORDER BY LENGTH(emp_name) DESC。但函数会阻止索引使用,大数据量时性能较差。
小结
ORDER BY决定结果集的呈现顺序,不带则顺序未定义- 支持多列排序、表达式排序和别名引用
- 避免使用字段位置序号排序,应使用列名
- 大数据量排序应考虑索引优化
NULL默认在升序时排最前,可用column IS NULL自定义位置
下一章引子:排序后的结果可能仍然很多,如果只想看前几条怎么办?