2.18 sql排序查询(ORDER BY、ASC、DESC)

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 分步操作

  1. 先写不带ORDER BY的查询,看原始顺序(通常按主键或插入顺序)。

  2. 加上ORDER BY指定字段。

  3. 决定升序还是降序。

  4. 执行并观察顺序变化。

避坑提醒

  • 字符串类型的数字排序可能不符合预期(如'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 分步操作

  1. 确定第一排序字段和方向。

  2. 确定第二排序字段和方向。

  3. 依次写在ORDER BY后面,用逗号分隔。

  4. 执行验证。

避坑提醒

  • 多字段排序时,每个字段都要单独指定方向(如果不写,默认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 分步操作

  1. 先写出带表达式的查询,确认表达式正确。

  2. ORDER BY中直接写表达式或别名。

  3. 执行验证。

避坑提醒

  • 表达式排序可能会影响性能,因为要对每一行计算。

  • 别名在ORDER BY中可用(因为ORDER BYSELECT之后执行),但在WHERE中不可用。

我的踩坑经历 :我写过SELECT amount * quantity AS total FROM orders ORDER BY total,没问题。但后来想在WHERE中用WHERE total > 1000,结果报错。因为WHERESELECT之前执行,别名还不存在。

排序与条件筛选的配合

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 分步操作

  1. 先写WHERE条件筛选出目标数据。

  2. 加上ORDER BY排序。

  3. 可选加上LIMIT限制行数。

  4. 执行验证。

避坑提醒

  • ORDER BY一定要放在LIMIT前面,否则语法错误。

  • LIMIT是在排序之后取前N行,所以必须先排序再限制。

实操避坑提醒 :如果要对分组后的结果排序(如每个类目下的商品销量排名),需要用到窗口函数ROW_NUMBER(),普通ORDER BY只能全局排序。

综合实操案例:服饰类目店铺月度商品销量TOP榜与用户消费排行

8.1 案例背景

某服饰类目店铺需要生成以下排行榜:

  1. 商品销量TOP 5(按总销量quantity降序)。

  2. 高价值用户消费排行(按用户总消费金额降序,需聚合)。

  3. 女装类目中,按销售额排序(金额*数量)的TOP 3商品。

  4. 最新订单优先显示(按时间倒序),同时按金额降序(相同时间金额高的在前)。

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配合,你就能轻松做出各类排行榜和优先级分析。

有问题的评论区留言,我看到会回复。

相关推荐
m0_377618232 小时前
mysql数据库如何通过调整读取策略提升性能_开启innodb_read_ahead
jvm·数据库·python
2301_814809862 小时前
MongoDB开启认证后应用程序出现断连假死现象
jvm·数据库·python
m0_678485452 小时前
mysql如何对比备份数据与线上数据_编写自动化校验脚本
jvm·数据库·python
石工记2 小时前
postgresql18 安装-运行
数据库·postgresql
DashVector2 小时前
AI Agent 接入 Zvec (一):MCP 篇
数据库·人工智能·后端
2401_865439632 小时前
C#怎么将控制台输出保存到TXT_C#如何重定向输出流【源码】
jvm·数据库·python
2301_815279522 小时前
Golang和Node.js哪个适合后端_Golang Node对比教程【实战】
jvm·数据库·python
m0_748839492 小时前
CSS如何制作圆形头像盒子_设置border-radius-50%
jvm·数据库·python
Wyz201210243 小时前
如何进行SQL字符串大小写转换_运用UPPER与LOWER函数
jvm·数据库·python