📊 MySQL 排序

ORDER BY 排序和多字段排序的完整指南

ORDER BY 简介

ORDER BY 子句用于对查询结果进行排序。可以按一个或多个列进行升序(ASC)或降序(DESC)排序。如果不指定排序方向,默认为升序。

ORDER BY 的特点:
  • 对查询结果进行排序
  • 支持单列或多列排序
  • 支持升序(ASC)和降序(DESC)
  • 可以使用列名、列别名或列位置
  • NULL 值的排序规则

基本语法

单列排序

-- 升序排序(默认) SELECT * FROM table_name ORDER BY column_name; -- 显式指定升序 SELECT * FROM table_name ORDER BY column_name ASC; -- 降序排序 SELECT * FROM table_name ORDER BY column_name DESC;

多列排序

-- 多列排序 SELECT * FROM table_name ORDER BY column1 ASC, column2 DESC, column3;

使用列位置排序

-- 按第2列和第3列排序 SELECT name, age, salary FROM employees ORDER BY 2, 3 DESC;

实际示例

示例数据准备

-- 创建员工表 CREATE TABLE employees ( id INT PRIMARY KEY, name VARCHAR(50), department VARCHAR(50), salary DECIMAL(10,2), hire_date DATE, age INT ); -- 插入测试数据 INSERT INTO employees VALUES (1, '张三', '技术部', 8000.00, '2020-01-15', 28), (2, '李四', '销售部', 6000.00, '2019-03-20', 32), (3, '王五', '技术部', 9500.00, '2021-06-10', 26), (4, '赵六', '人事部', 5500.00, '2018-11-05', 35), (5, '钱七', '技术部', 7500.00, '2020-08-12', 29), (6, '孙八', '销售部', 6500.00, '2019-12-01', 31);

基本排序示例

按薪资升序排序

SELECT name, department, salary FROM employees ORDER BY salary;
namedepartmentsalary
赵六人事部5500.00
李四销售部6000.00
孙八销售部6500.00
钱七技术部7500.00
张三技术部8000.00
王五技术部9500.00

按薪资降序排序

SELECT name, department, salary FROM employees ORDER BY salary DESC;

按部门和薪资排序

SELECT name, department, salary FROM employees ORDER BY department ASC, salary DESC;
namedepartmentsalary
赵六人事部5500.00
孙八销售部6500.00
李四销售部6000.00
王五技术部9500.00
张三技术部8000.00
钱七技术部7500.00

高级排序技巧

使用表达式排序

-- 按年薪排序 SELECT name, salary, salary * 12 as annual_salary FROM employees ORDER BY salary * 12 DESC; -- 按姓名长度排序 SELECT name, LENGTH(name) as name_length FROM employees ORDER BY LENGTH(name), name;

使用 CASE 语句排序

-- 自定义部门排序优先级 SELECT name, department, salary FROM employees ORDER BY CASE department WHEN '技术部' THEN 1 WHEN '销售部' THEN 2 WHEN '人事部' THEN 3 ELSE 4 END, salary DESC;

日期排序

-- 按入职日期排序 SELECT name, hire_date, DATEDIFF(NOW(), hire_date) as days_employed FROM employees ORDER BY hire_date DESC; -- 按入职年份和月份排序 SELECT name, hire_date FROM employees ORDER BY YEAR(hire_date) DESC, MONTH(hire_date) DESC;

NULL 值排序

-- NULL 值排序(MySQL 中 NULL 值排在最前面) SELECT name, bonus FROM employees ORDER BY bonus; -- NULL 值在前 -- 将 NULL 值排在最后 SELECT name, bonus FROM employees ORDER BY bonus IS NULL, bonus; -- 将 NULL 值排在最前 SELECT name, bonus FROM employees ORDER BY bonus IS NOT NULL, bonus;

ORDER BY 与其他子句结合

ORDER BY + WHERE

-- 查询技术部员工,按薪资降序排列 SELECT name, salary FROM employees WHERE department = '技术部' ORDER BY salary DESC;

ORDER BY + LIMIT

-- 查询薪资最高的3名员工 SELECT name, salary FROM employees ORDER BY salary DESC LIMIT 3; -- 查询薪资第4-6名的员工 SELECT name, salary FROM employees ORDER BY salary DESC LIMIT 3 OFFSET 3;

ORDER BY + GROUP BY

-- 按部门统计平均薪资,并按平均薪资排序 SELECT department, AVG(salary) as avg_salary, COUNT(*) as emp_count FROM employees GROP BY department ORDER BY avg_salary DESC;

ORDER BY + HAVING

-- 查询平均薪资大于7000的部门,按平均薪资排序 SELECT department, AVG(salary) as avg_salary FROM employees GROUP BY department HAVING AVG(salary) > 7000 ORDER BY avg_salary DESC;

性能优化

排序性能优化技巧:
  • 在排序列上创建索引
  • 避免对大量数据进行排序
  • 使用 LIMIT 限制结果集大小
  • 考虑使用覆盖索引
  • 避免在函数或表达式上排序

索引优化示例

-- 为排序列创建索引 CREATE INDEX idx_salary ON employees(salary); CREATE INDEX idx_dept_salary ON employees(department, salary); -- 复合索引的排序优化 SELECT * FROM employees WHERE department = '技术部' ORDER BY salary DESC; -- 可以使用 idx_dept_salary 索引

查看排序执行计划

-- 查看查询执行计划 EXPLAIN SELECT * FROM employees ORDER BY salary DESC; -- 查看详细执行信息 EXPLAIN FORMAT=JSON SELECT * FROM employees ORDER BY salary DESC;

实际应用场景

1. 排行榜查询

-- 销售排行榜 SELECT salesperson, SUM(amount) as total_sales FROM sales GROUP BY salesperson ORDER BY total_sales DESC LIMIT 10;

2. 分页查询

-- 分页查询员工列表(第2页,每页10条) SELECT id, name, department, salary FROM employees ORDER BY id LIMIT 10 OFFSET 10;

3. 时间序列数据

-- 按时间倒序查询最新订单 SELECT order_id, customer_id, order_date, total_amount FROM orders ORDER BY order_date DESC, order_id DESC LIMIT 20;

4. 多维度排序

-- 学生成绩排序:先按总分,再按数学成绩,最后按姓名 SELECT student_name, math_score, english_score, (math_score + english_score) as total_score FROM student_scores ORDER BY total_score DESC, math_score DESC, student_name;

常见错误和注意事项

常见错误:
  • 在 GROUP BY 中使用 ORDER BY 时的列选择错误
  • 忘记考虑 NULL 值的排序影响
  • 在大数据集上进行无索引排序
  • 混淆列位置和列名的使用

GROUP BY 与 ORDER BY 的注意事项

-- 错误:ORDER BY 中的列必须在 SELECT 中或者是聚合函数 SELECT department, COUNT(*) FROM employees GROUP BY department ORDER BY salary; -- 错误:salary 不在 SELECT 中 -- 正确:使用聚合函数 SELECT department, COUNT(*) FROM employees GROUP BY department ORDER BY AVG(salary) DESC;

字符串排序的字符集问题

-- 指定排序规则 SELECT name FROM employees ORDER BY name COLLATE utf8mb4_unicode_ci; -- 中文排序 SELECT name FROM employees ORDER BY CONVERT(name USING gbk) COLLATE gbk_chinese_ci;