SQL统计Top N并归并“其他”的核心是用UNION ALL拼接两部分:先取排序前N行,再将剩余数据聚合为一行“其他”;需确保字段数、类型、顺序一致,避免重复计算且排序稳定。

SQL 统计 Top N 并把剩余归为“其他”,核心是用 UNION ALL 拼接两部分:前 N 行 + 剩余行聚合为一行“其他”。关键在于避免重复计算、保证排序一致、正确汇总“其他”值。
先取 Top N,再算“其他”的总量
标准做法是写两个子查询,用 UNION ALL 合并:
- 第一部分:按指标排序取 LIMIT N(MySQL/PostgreSQL)或 TOP N(SQL Server),注意加上 ROW_NUMBER() 或用子查询确保稳定排序
- 第二部分:排除这 N 行的数据,SUM/ COUNT 聚合剩余值,并固定命名为“其他”
- 两部分字段数、类型、顺序必须完全一致,否则 UNION 会报错
示例(统计销量前 3 的商品,其余归为“其他”):
SELECT product, sales FROM (
SELECT product, sales, ROW_NUMBER() OVER (ORDER BY sales DESC) AS rn
FROM orders
) t WHERE rn <= 3
UNION ALL
SELECT '其他' AS product, SUM(sales) AS sales
FROM orders
WHERE product NOT IN (
SELECT product FROM (
SELECT product, ROW_NUMBER() OVER (ORDER BY sales DESC) AS rn
FROM orders
) t WHERE rn <= 3
);
用条件聚合一步实现(更简洁,适合简单场景)
如果只关心一个汇总指标(比如总销售额),可用 CASE + SUM 配合窗口函数,避免多次扫描表:
- 先用 ROW_NUMBER() 标记每行排名
- 用 SUM(CASE WHEN rn
- 用 SUM(CASE WHEN rn > 3 THEN sales ELSE 0 END) 得“其他”总和
- 再用 UNION 或子查询把明细和“其他”拼成同一列结构
示例(返回 4 行:3 个商品 + 1 行“其他”):
WITH ranked AS (
SELECT product, sales,
ROW_NUMBER() OVER (ORDER BY sales DESC) AS rn
FROM orders
)
SELECT
CASE WHEN rn <= 3 THEN product ELSE '其他' END AS product,
SUM(sales) AS sales
FROM ranked
GROUP BY CASE WHEN rn <= 3 THEN product ELSE '其他' END
ORDER BY MAX(CASE WHEN rn <= 3 THEN rn END) NULLS LAST;
注意去重与并列情况
真实数据常有相同销量的商品,直接用 ROW_NUMBER() 会强行分先后,可能漏掉并列第 3 名。这时建议改用:
- RANK():并列名次跳过后续名次(如 1,2,2,4),适合“取所有排名 ≤ N 的记录”
- DENSE_RANK():并列不跳号(如 1,2,2,3),适合严格限制最多 N 个不同名次
- 若需恰好 N 行且允许截断并列项,ROW_NUMBER() 更可控;若要保留所有并列 Top N,用 RANK() + WHERE rank
不同数据库的语法微调
MySQL 8.0+、PostgreSQL、SQL Server 2017+ 都支持窗口函数,写法基本一致。但注意:
- MySQL 5.7 或更早版本不支持窗口函数 → 只能用变量或自连接模拟排名,再配合 UNION
- SQL Server 用 TOP N + ORDER BY,但子查询中 TOP 不支持直接用于 UNION 的右支 → 需套一层 CTE 或子查询
- Oracle 用 ROWNUM 需嵌套(因 ROWNUM 分配发生在 ORDER BY 之前),必须先排序再加 ROWNUM
不复杂但容易忽略细节,关键是理清逻辑顺序:排名 → 切分 → 分别聚合 → 对齐字段合并。

