求简洁SQL实现‘一年一列’表转换,替代多JOIN/WHERE方案
行转列(Pivot)简化方案:将年份转为单独列
针对你提到的fruits表行转列需求,完全不需要用繁琐的多次自连接,以下是几种更简洁的实现方式,适配不同SQL方言:
通用条件聚合(所有SQL数据库支持)
这是最普适的写法,比自连接简洁得多,仅需为每个年份添加一行CASE语句:
SELECT fruit, SUM(CASE WHEN year = 2021 THEN value END) AS `2021`, SUM(CASE WHEN year = 2022 THEN value END) AS `2022`, SUM(CASE WHEN year = 2023 THEN value END) AS `2023`, SUM(CASE WHEN year = 2024 THEN value END) AS `2024` -- 新增年份时,复制上述行并修改年份即可 FROM fruits GROUP BY fruit;
注:如果每个fruit+year组合唯一,用MAX()替代SUM()效果一致
专用PIVOT语法(部分数据库支持)
SQL Server / Power BI
直接使用原生PIVOT关键字,语法更紧凑:
SELECT * FROM fruits PIVOT ( SUM(value) -- 聚合函数,根据实际需求选SUM/MAX等 FOR year IN ([2021], [2022], [2023], [2024]) -- 列出所有目标年份列 ) AS pivoted_fruits;
PostgreSQL(需tablefunc扩展)
先启用扩展,再用crosstab函数实现:
-- 首次使用需启用扩展 CREATE EXTENSION IF NOT EXISTS tablefunc; SELECT * FROM crosstab( 'SELECT fruit, year, value FROM fruits ORDER BY 1,2', 'SELECT DISTINCT year FROM fruits ORDER BY 1' ) AS ct ( fruit TEXT, "2021" INT, "2022" INT, "2023" INT, "2024" INT -- 按实际年份和value的数据类型补充列定义 );
动态SQL(适配年份多达上百个的场景)
如果年份数量极多,手动写列不现实,可通过动态SQL自动生成语句,以MySQL为例:
SET @sql = NULL; -- 自动拼接所有年份的CASE语句 SELECT GROUP_CONCAT(DISTINCT CONCAT( 'SUM(CASE WHEN year = ', year, ' THEN value END) AS `', year, '`' ) ) INTO @sql FROM fruits; -- 组装完整查询语句 SET @sql = CONCAT('SELECT fruit, ', @sql, ' FROM fruits GROUP BY fruit'); -- 执行动态SQL PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
其他数据库(如PostgreSQL、SQL Server)也支持类似的动态SQL生成逻辑,核心是通过系统表或查询结果自动拼接列定义。
内容的提问来源于stack exchange,提问作者code_beginner
相关产品推荐
相关产品推荐

