直接用group by+聚合函数就能实现核心功能,无需额外工具;行维度放group by,值字段套sum/count等聚合函数,列维度用case when+聚合手动展开,并注意else 0处理null、多维分组需同步写入group by和select。

直接用 GROUP BY + 聚合函数就能实现核心功能,不需要额外工具或存储过程。
用 GROUP BY 做基础行列分组汇总
Excel 透视表的“行标签+列标签+值汇总”在 SQL 中对应的是多字段 GROUP BY 加 SUM()、COUNT() 等聚合函数。关键不是“模仿界面”,而是明确你要按哪些维度切分数据、对哪列做统计。
常见错误是只写一个分组字段却想看多个维度交叉结果,比如想按部门和年份统计销售额,却只写 GROUP BY department —— 这会导致年份信息被压缩掉,无法区分各年变化。
- 要同时按部门和年份分组:必须写
GROUP BY department, YEAR(order_date) - 聚合字段不能出现在
SELECT中却不参与分组或聚合,否则多数数据库(如 MySQL 5.7+、PostgreSQL)会报错ERROR 1055 - MySQL 8.0+ 默认开启
ONLY_FULL_GROUP_BY,这点比旧版更严格,也更符合 SQL 标准
用 CASE WHEN + SUM() 实现“列展开”(类似透视列)
Excel 里把“产品类别”拖到列区域,就自动变成 A列=手机、B列=电脑 的横向结构 —— SQL 没有原生“动态列”语法,但可以用条件聚合硬编码实现静态列展开。
这种写法本质是:对每一行,判断它属于哪个类别,属于就取值,否则取 0,再整体求和。
SELECT region, SUM(CASE WHEN product = '手机' THEN sales ELSE 0 END) AS 手机, SUM(CASE WHEN product = '电脑' THEN sales ELSE 0 END) AS 电脑, SUM(CASE WHEN product = '平板' THEN sales ELSE 0 END) AS 平板 FROM orders GROUP BY region;
- 注意
ELSE 0很重要:不写会导致该行对应列为NULL,SUM()会跳过NULL,结果偏小 - 类别必须提前知道且数量有限;如果产品种类太多或经常变动,这种写法维护成本高,不如在应用层处理
- PostgreSQL 可用
FILTER语法替代(如SUM(sales) FILTER (WHERE product = '手机')),语义更清晰,但 MySQL 不支持
避免用 PIVOT(除非你确定数据库支持且场景匹配)
SQL Server 和 Oracle 有 PIVOT 关键字,看起来更像 Excel,但实际使用限制多、可读性差、调试困难。
比如 SQL Server 的 PIVOT 要求聚合列必须是单值,且列名必须写死,还容易和子查询嵌套出错。出问题时错误信息往往指向“无效的列名”,而不是告诉你哪步逻辑错了。
- MySQL 完全不支持
PIVOT,别搜教程硬套 - SQLite、PostgreSQL 也不支持标准
PIVOT,有些第三方扩展提供类似功能,但稳定性和兼容性没保障 - 真正需要动态列(比如用户自选维度)的场景,应该交给 BI 工具(如 Metabase、Superset)或后端代码生成 SQL,而不是在 SQL 层强行模拟
最易被忽略的一点:GROUP BY 的字段顺序会影响结果排序,但不保证输出顺序 —— 如果你需要固定行列顺序(比如年份从 2021 到 2024),必须显式加 ORDER BY;另外,空值(NULL)在分组中会被单独归为一组,如果业务上“未填部门”和“其他部门”含义不同,得提前用 COALESCE(department, '未知') 处理。











