2.18 排序查询(ORDER BY、ASC、DESC)
在电商数据分析中,你几乎每天都要用到排序:
-
销量排行榜(TOP10商品)。
-
高价值用户排行(消费金额最高的用户)。
-
最新订单优先显示(按时间倒序)。
-
活动效果对比(按ROI排序)。
ORDER BY子句就是用来做排序的。这一章我会带你彻底搞懂ORDER BY的各种用法:单字段排序、多字段排序、按表达式排序、与LIMIT配合取TOP N。学完之后,你能轻松做出各类排行榜和优先级分析。
学习前准备:
-
已完成MySQL安装(参考系列前几章)
-
已安装DBeaver或Navicat
-
准备一个练习数据库,比如
orderby_demo
学习前环境准备
步骤1:确保MySQL服务已启动。
步骤2:创建练习数据库和表,并插入示例数据。
sql
CREATE DATABASE orderby_demo
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE orderby_demo;
-- 订单表(包含用户、店铺、金额、销量、时间等)
CREATE TABLE orders (
order_id VARCHAR(50) PRIMARY KEY,
user_id INT NOT NULL,
shop_name VARCHAR(50) NOT NULL,
product_name VARCHAR(100),
amount DECIMAL(10,2) NOT NULL,
quantity INT NOT NULL DEFAULT 1,
order_status VARCHAR(20) NOT NULL,
create_time DATETIME NOT NULL
);
INSERT INTO orders VALUES
('ORD001', 1001, '女装旗舰店', '碎花连衣裙', 299.00, 2, '已支付', '2025-06-01 10:00:00'),
('ORD002', 1002, '女装旗舰店', '纯棉T恤', 189.00, 3, '已取消', '2025-06-01 11:00:00'),
('ORD003', 1003, '男装专营店', '牛仔裤', 599.00, 1, '已支付', '2025-06-02 09:30:00'),
('ORD004', 1001, '女装旗舰店', '雪纺衫', 399.00, 1, '已支付', '2025-06-03 14:20:00'),
('ORD005', 1004, '童装店', '儿童T恤', 99.00, 5, '已完成', '2025-06-03 16:00:00'),
('ORD006', 1005, '女装旗舰店', '真丝连衣裙', 1299.00, 1, '已支付', '2025-06-04 08:30:00'),
('ORD007', 1002, '男装专营店', '休闲短裤', 89.00, 2, '已取消', '2025-06-04 10:00:00'),
('ORD008', 1006, '女装旗舰店', '基础打底衫', 89.00, 10, '已支付', '2025-06-05 09:00:00'),
('ORD009', 1007, '男装专营店', 'Polo衫', 259.00, 1, '已支付', '2025-06-05 14:00:00');
ORDER BY排序基础认知
ORDER BY子句用于对查询结果集进行排序 。它通常放在SQL语句的末尾(LIMIT之前)。
基本语法:
sql
SELECT 列 FROM 表 ORDER BY 列1 [ASC|DESC], 列2 [ASC|DESC], ...;
-
ASC:升序(默认),从小到大,从早到晚。 -
DESC:降序,从大到小,从晚到早。
在电商数据分析中的核心用途:
-
找出销量最高的商品(
ORDER BY quantity DESC)。 -
找出消费金额最高的用户(
ORDER BY amount DESC)。 -
最新订单优先(
ORDER BY create_time DESC)。 -
结合
LIMIT做TOP N分析。
我的踩坑经历 :第一次用
ORDER BY时,我写了ORDER BY amount,结果金额最小的排在最前面。我以为默认是降序,其实默认是升序。要降序必须写DESC。
单字段排序
4.1 基础语法
sql
SELECT * FROM 表 ORDER BY 列名 [ASC|DESC];
4.2 电商实操案例
案例一:按订单金额升序(从低到高)
sql
SELECT order_id, amount FROM orders ORDER BY amount;
预期结果:89, 89, 99, 189, 259, 299, 399, 599, 1299。
案例二:按订单金额降序(从高到低)
sql
SELECT order_id, amount FROM orders ORDER BY amount DESC;
预期结果:1299, 599, 399, 299, 259, 189, 99, 89, 89。
案例三:按下单时间降序(最新订单在前)
sql
SELECT order_id, create_time FROM orders ORDER BY create_time DESC;
预期结果:ORD009(6月5日), ORD008(6月5日), ORD007(6月4日), ORD006(6月4日), ORD005(6月3日), ORD004(6月3日), ORD003(6月2日), ORD002(6月1日), ORD001(6月1日)。
4.3 分步操作
-
先写不带
ORDER BY的查询,看原始顺序(通常按主键或插入顺序)。 -
加上
ORDER BY指定字段。 -
决定升序还是降序。
-
执行并观察顺序变化。
避坑提醒:
-
字符串类型的数字排序可能不符合预期(如'10' < '2')。确保数据类型正确。
-
ORDER BY可以使用不在SELECT列表中的列。
实操避坑提醒 :如果对文本字段排序,MySQL默认不区分大小写,但区分字符集。如果要按拼音排序,可能需要设置排序规则(
COLLATE)。
多字段联合排序
5.1 基础语法
sql
SELECT * FROM 表 ORDER BY 列1 [ASC|DESC], 列2 [ASC|DESC], ...;
先按第一列排序,第一列相同再按第二列,以此类推。
5.2 电商实操案例
案例一:先按店铺名称升序,再按订单金额降序(同一店铺内金额高的在前)
sql
SELECT shop_name, amount FROM orders
ORDER BY shop_name ASC, amount DESC;
预期结果:
-
女装旗舰店:1299, 399, 299, 189, 89
-
男装专营店:599, 259, 89
-
童装店:99
案例二:先按订单状态(已支付在前),再按金额降序
sql
SELECT order_status, amount FROM orders
ORDER BY order_status = '已支付' DESC, amount DESC;
注意:这里用了表达式(后面会讲),也可以直接用CASE。简单方式:先按状态分组,再按金额排序。
sql
SELECT order_status, amount FROM orders
ORDER BY CASE order_status WHEN '已支付' THEN 1 WHEN '已完成' THEN 2 WHEN '已取消' THEN 3 ELSE 4 END, amount DESC;
5.3 分步操作
-
确定第一排序字段和方向。
-
确定第二排序字段和方向。
-
依次写在
ORDER BY后面,用逗号分隔。 -
执行验证。
避坑提醒:
-
多字段排序时,每个字段都要单独指定方向(如果不写,默认ASC)。
-
NULL值的排序:MySQL中NULL被视为最小值(升序排在最前,降序排在最后)。
我的踩坑经历 :我写过
ORDER BY shop_name, amount DESC,以为先按店铺升序,再按金额降序。但实际是shop_name升序,amount也升序(因为没写DESC)。后来改成ORDER BY shop_name, amount DESC才正确。
表达式与别名排序
6.1 基础语法
可以对表达式(计算字段)排序,也可以对列别名排序。
sql
SELECT 列, 表达式 AS 别名 FROM 表 ORDER BY 表达式;
SELECT 列, 表达式 AS 别名 FROM 表 ORDER BY 别名;
6.2 电商实操案例
案例一:按订单总价(金额×数量)降序
sql
SELECT order_id, amount, quantity, amount * quantity AS total_value
FROM orders
ORDER BY total_value DESC;
预期结果 :ORD008(8910=890), ORD006(12991=1299) --- 1299 > 890,所以ORD006第一,ORD008第二。
案例二:按商品毛利率排序(假设有成本表,这里用简化)
没有成本字段,演示表达式排序。
sql
SELECT product_name, amount, amount * 0.6 AS estimated_profit
FROM orders
ORDER BY estimated_profit DESC;
案例三:按订单日期(只取月份)排序
sql
SELECT order_id, create_time, MONTH(create_time) AS month_num
FROM orders
ORDER BY month_num;
6.3 分步操作
-
先写出带表达式的查询,确认表达式正确。
-
在
ORDER BY中直接写表达式或别名。 -
执行验证。
避坑提醒:
-
表达式排序可能会影响性能,因为要对每一行计算。
-
别名在
ORDER BY中可用(因为ORDER BY在SELECT之后执行),但在WHERE中不可用。
我的踩坑经历 :我写过
SELECT amount * quantity AS total FROM orders ORDER BY total,没问题。但后来想在WHERE中用WHERE total > 1000,结果报错。因为WHERE在SELECT之前执行,别名还不存在。
排序与条件筛选的配合
7.1 基础语法
WHERE先过滤行,ORDER BY再对结果排序。
sql
SELECT * FROM 表 WHERE 条件 ORDER BY 列;
7.2 电商实操案例
案例一:查询女装旗舰店已支付订单,按金额降序
sql
SELECT order_id, shop_name, amount FROM orders
WHERE shop_name = '女装旗舰店' AND order_status = '已支付'
ORDER BY amount DESC;
预期结果:1299, 399, 299, 89(ORD008的89)。
案例二:查询6月份金额大于200的订单,按时间升序
sql
SELECT order_id, amount, create_time FROM orders
WHERE amount > 200 AND create_time BETWEEN '2025-06-01' AND '2025-06-30'
ORDER BY create_time ASC;
预期结果:ORD001(299), ORD003(599), ORD004(399), ORD006(1299), ORD009(259)。
案例三:销量TOP 3的商品(按数量降序,取前3)
sql
SELECT product_name, quantity FROM orders
ORDER BY quantity DESC
LIMIT 3;
预期结果:基础打底衫(10), 儿童T恤(5), 纯棉T恤(3)。
7.3 分步操作
-
先写
WHERE条件筛选出目标数据。 -
加上
ORDER BY排序。 -
可选加上
LIMIT限制行数。 -
执行验证。
避坑提醒:
-
ORDER BY一定要放在LIMIT前面,否则语法错误。 -
LIMIT是在排序之后取前N行,所以必须先排序再限制。
实操避坑提醒 :如果要对分组后的结果排序(如每个类目下的商品销量排名),需要用到窗口函数
ROW_NUMBER(),普通ORDER BY只能全局排序。
综合实操案例:服饰类目店铺月度商品销量TOP榜与用户消费排行
8.1 案例背景
某服饰类目店铺需要生成以下排行榜:
-
商品销量TOP 5(按总销量
quantity降序)。 -
高价值用户消费排行(按用户总消费金额降序,需聚合)。
-
女装类目中,按销售额排序(金额*数量)的TOP 3商品。
-
最新订单优先显示(按时间倒序),同时按金额降序(相同时间金额高的在前)。
8.2 分步操作
步骤1:商品销量TOP 5(不考虑聚合,直接按订单中的数量排序)
sql
SELECT product_name, quantity FROM orders
WHERE product_name IS NOT NULL
ORDER BY quantity DESC
LIMIT 5;
预期结果:基础打底衫(10), 儿童T恤(5), 纯棉T恤(3), 碎花连衣裙(2), 休闲短裤(2)。
步骤2:高价值用户消费排行(需要按用户分组聚合)
sql
SELECT user_id, SUM(amount) AS total_spent
FROM orders
WHERE order_status IN ('已支付', '已完成')
GROUP BY user_id
ORDER BY total_spent DESC;
预期结果:1005(1299), 1001(299+399=698), 1003(599), 1007(259), 1006(89), 1004(99? 99小于89? 实际1004童装店99元,但ORD005是已完成,应该计入,所以1004=99,1006=89,顺序:1005,1001,1003,1007,1004,1006。还有1002? 1002订单都是已取消,不计入,所以不出现。
步骤3:女装类目中销售额(金额×数量)TOP 3
sql
SELECT product_name, amount, quantity, amount * quantity AS sales
FROM orders
WHERE shop_name = '女装旗舰店'
ORDER BY sales DESC
LIMIT 3;
预期结果 :ORD008(基础打底衫 8910=890), ORD006(真丝连衣裙12991=1299), 实际上1299>890,所以ORD006第一,ORD008第二,ORD004(399*1=399)第三。
步骤4:最新订单优先,同时按金额降序
sql
SELECT order_id, create_time, amount FROM orders
ORDER BY create_time DESC, amount DESC;
预期结果:同一时间(6月5日)ORD009(259)和ORD008(89),金额大的在前:ORD009, ORD008;6月4日ORD006(1299), ORD007(89) → ORD006, ORD007;依此类推。
8.3 结果验证
执行所有查询,检查逻辑一致性(如TOP 5数量正确,排序顺序正确)。
📌 电商数据合规提示 :在用户消费排行中,
user_id是内部匿名ID,不涉及个人敏感信息。但如果用户表关联了手机号,绝对不要在排行榜中输出手机号。另外,销量TOP榜涉及商品明细,属于经营数据,分享时注意保密。
本章踩坑清单与合规总结
9.1 新手常见踩坑
| 错误 | 原因 | 正确做法 |
|---|---|---|
忘记写DESC导致升序 |
默认ASC | 明确指定方向 |
| 多字段排序时方向写错位置 | 语法错误 | 每个字段单独跟ASC/DESC |
ORDER BY放在LIMIT后面 |
语法错误 | ORDER BY必须在LIMIT之前 |
| 对表达式排序时写了重复计算 | 可读性差 | 用别名简化 |
| 对文本数字排序结果奇怪 | 数据类型问题 | 转为数值再排序 |
9.2 性能优化建议
-
为经常排序的字段建立索引(如
create_time)。 -
大表排序时尽量配合
WHERE缩小范围。 -
避免对非索引字段排序,会导致文件排序(filesort)。
结语
ORDER BY是SQL中让数据"有序"的关键。掌握单字段、多字段、表达式排序以及与LIMIT配合,你就能轻松做出各类排行榜和优先级分析。
有问题的评论区留言,我看到会回复。