SQL中Pivot实现需求:根据给定源表生成指定结构输出结果
实现SQL数据转换:从宽表到目标结构
我来帮你搞定这个数据转换的需求!这个场景其实是**先列转行(Unpivot)再行转列(Pivot)**的组合操作,咱们一步步拆解实现:
核心思路
- 列转行(Unpivot):把原始表中
Jan、Feb这类月份列,转换成Month(月份名称)和Value(对应数值)的行数据,让每个月份的数值都变成单独的一行。 - 行转列(Pivot):把第一步得到的
Tag列(Secondary、Primary)转换成独立的列,让每个Brand+Year+Month组合下,能同时显示两个Tag的数值。
方案1:SQL Server原生PIVOT/UNPIVOT写法
如果你的数据库是SQL Server(支持原生PIVOT语法),可以用下面的语句:
SELECT Brand, Year, Month, Secondary, Primary FROM ( -- 第一步:Unpivot,把月份列转成行 SELECT Brand, Year, Tag, Month, Value FROM YourOriginalTable -- 替换成你的实际表名 UNPIVOT ( Value FOR Month IN (Jan, Feb) ) AS Unpvt ) AS PivotSource -- 第二步:Pivot,把Tag转成列 PIVOT ( MAX(Value) FOR Tag IN (Secondary, Primary) ) AS Pvt ORDER BY Brand, Year DESC, Month;
说明
- 这里用
MAX(Value)是因为每个Brand+Year+Month+Tag组合只有唯一值,用MAX/MIN/AVG都能得到正确结果,选哪个都可以。 - 最终结果会自动把没有对应Tag的数值显示为
NULL,完美匹配你要的输出。
方案2:通用CASE WHEN写法(兼容所有数据库)
如果你的数据库不支持原生PIVOT(比如MySQL、SQLite等),这个兼容性拉满的写法更合适:
SELECT Brand, Year, Month, MAX(CASE WHEN Tag = 'Secondary' THEN Value END) AS Secondary, MAX(CASE WHEN Tag = 'Primary' THEN Value END) AS Primary FROM ( -- 第一步:用UNION ALL模拟Unpivot,把每个月份拆成行 SELECT Brand, Year, Tag, 'Jan' AS Month, Jan AS Value FROM YourOriginalTable UNION ALL SELECT Brand, Year, Tag, 'Feb' AS Month, Feb AS Value FROM YourOriginalTable ) AS UnpvtData GROUP BY Brand, Year, Month ORDER BY Brand, Year DESC, Month;
说明
- 用
UNION ALL把Jan和Feb列分别拆成独立的行,实现列转行的效果。 - 分组后通过
CASE WHEN提取对应Tag的数值,没有匹配到的Tag会返回NULL,完全符合期望的结果结构。
内容的提问来源于stack exchange,提问作者Rubina K
相关产品推荐
相关产品推荐

