最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
如何编写SQL以查询各省份销售额前十名的城市汇总数据?
时间:2026-07-01 09:41:56 编辑:袖梨 来源:一聚教程网
必须用窗口函数 ROW_NUMBER() 按省份分区排序,才能实现各省独立取前10;错误做法是 GROUP BY 后直接 ORDER BY + LIMIT,结果为全国 Top10。
用窗口函数 ROW_NUMBER() 排名,避免 GROUP BY 后丢失城市粒度
直接对省份 + 城市分组求和再排序,容易误用 ORDER BY 仅作用于最终结果集——这没法保证“每个省内独立取前10”。必须用窗口函数在分组聚合后、按省份分区排序。
常见错误是写成 SELECT province, city, SUM(sales) FROM t GROUP BY province, city ORDER BY SUM(sales) DESC LIMIT 10,这返回的是全国销售额 Top10,不是各省 Top10。
正确做法分两步:先聚合(GROUP BY province, city),再用 ROW_NUMBER() OVER (PARTITION BY province ORDER BY SUM(sales) DESC) 标记名次:
SELECT province, city, sales_sumFROM ( SELECT province, city, SUM(sales) AS sales_sum, ROW_NUMBER() OVER (PARTITION BY province ORDER BY SUM(sales) DESC) AS rn FROM orders GROUP BY province, city) rankedWHERE rn <= 10;
注意 ROW_NUMBER() 和 RANK() 的并列处理差异
如果某省第10名有多个城市销售额相同,ROW_NUMBER() 会强制给唯一序号(比如 9、10、11),导致实际返回 11 行;而 RANK() 会并列(比如 9、10、10、12),此时 WHERE rn 可能漏掉并列的第10名。
- 要严格限制最多10行/省 → 用
ROW_NUMBER() - 要保留所有并列第10名 → 改用
RANK(),但 WHERE 条件得改成r (别漏改别名) - MySQL 8.0+、PostgreSQL、SQL Server 2017+、Oracle 都支持;SQLite 3.35+ 也支持,旧版不支持窗口函数
聚合前过滤脏数据,否则 SUM(sales) 结果失真
真实订单表常含 sales 为 NULL 或负值(退货)、province/city 为空或“未知”、“其他”等非标准值。这些不剔除,会导致:
-
SUM()忽略 NULL,但若整组都是 NULL,该城市不出现 → 看似“没数据”,实为脏数据掩盖 - 负销售额拉低排名,把本该进 Top10 的城市挤出去
- “华东”“华北”等大区名混在
province字段里,和真实省份同名分区 → 分区错乱
建议在子查询中加清洗条件:
WHERE sales > 0 AND province IS NOT NULL AND city NOT IN ('未知', '其他', '') AND province IN ('广东', '江苏', '浙江', ...)
大数据量时加复合索引提升性能
当 orders 表超千万行,上述查询可能慢在两处:按 province/city 分组扫描、以及窗口函数排序。单列索引效果有限。
推荐创建覆盖索引:
CREATE INDEX idx_province_city_sales ON orders (province, city, sales);
这个顺序很重要:province 在前支持分区裁剪,city 第二支持组内去重,sales 最后让 SUM() 和 ORDER BY 尽量走索引有序扫描,避免额外排序。
如果业务中经常查“某省 Top N”,还可考虑物化省份汇总表,但实时性要求高时,索引 + 窗口函数仍是更轻量的选择。
相关文章
- 绯色回响黎角色抽取攻略 07-01
- 洛克王国世界大耳帽兜怎么获得 大耳帽兜解锁方法详解 07-01
- 洛克王国世界阿米亚特在哪里捕捉 阿米亚特捕捉地点介绍 07-01
- 三国乱世霸王吕蒙怎么配队-吕蒙配队攻略 07-01
- Debian Spool 如何正确设置 07-01
- Linux Informix数据库版本选择指南 07-01