每个对象的最新一行:DISTINCT 不能替代排序
用分区窗口明确“每个客户最新订单”的行级选择规则。
问题与判断方法
DISTINCT 只能删除所有所选字段都相同的重复行。只要同一客户的金额或时间不同,多条订单仍会保留,因此它不能表达“每个客户只取最新一条”。减少 SELECT 字段来迎合 DISTINCT 还可能丢失真正需要的数据。
ROW_NUMBER 可以按 customer_id 分区,再按 created_at DESC 排序,为每个客户的最新记录标记 rn = 1。时间相同时应增加 id DESC 等唯一键,保证选择结果可重复。
另一种做法是先求每个客户的 MAX(created_at) 再连接原表,但并列时间可能重新产生多行。选择方案前要明确是否允许并列、需要哪些完整字段,以及相应复合索引的列顺序。
示例
示例数据表
表名:
orders| customer_id | amount | created_at |
|---|---|---|
| 101 | 1200 | 2026-01-03 |
| 102 | 900 | 2026-01-08 |
| 101 | 1500 | 2026-02-02 |
| 104 | 700 | 2026-02-15 |
优化前 / 不推荐
SELECT DISTINCT customer_id, amount, created_at FROM orders ORDER BY customer_id, created_at DESC;优化前运行结果
| customer_id | amount | created_at |
|---|---|---|
| 101 | 1500 | 2026-02-02 |
| 101 | 1200 | 2026-01-03 |
| 102 | 900 | 2026-01-08 |
| 104 | 700 | 2026-02-15 |
优化后 / 推荐
WITH ranked AS (SELECT customer_id, amount, created_at, ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY created_at DESC, id DESC) AS rn FROM orders) SELECT customer_id, amount, created_at FROM ranked WHERE rn = 1 ORDER BY customer_id;优化后运行结果
| customer_id | amount | created_at |
|---|---|---|
| 101 | 1500 | 2026-02-02 |
| 102 | 900 | 2026-01-08 |
| 104 | 700 | 2026-02-15 |
为什么这样更好:DISTINCT 仍保留 customer 101 的两条不同订单;ROW_NUMBER 按时间与 id 明确只取最新一条。
这篇内容是否清楚?
感谢反馈,我们会把它用于后续内容复核。