将两列透视值转为列名:SQL透视/逆透视结果不符求助
看起来你在处理SQL的行列转换时遇到了点小麻烦,我帮你调整一下查询语句,正好能得到你想要的结果!
原始数据表
先确认一下你的基础数据源:
| RowNamesCol1 | RowNamesCol2 | Col1 | Col2 |
|---|---|---|---|
| Col1Row1 | Col2Row1 | 1 | 4 |
| Col1Row2 | Col2Row2 | 2 | 5 |
| Col1Row3 | Col2Row3 | 3 | 6 |
你的需求回顾
你之前的查询语句得到的结果结构不符合预期,你想要的最终输出是:
| Col1Row1 | Col1Row2 | Col1Row3 | |
|---|---|---|---|
| RNC1 | Col2Row1 | Col2Row2 | Col2Row3 |
| Col1 | 1 | 2 | 3 |
| Col2 | 4 | 5 | 6 |
正确的SQL实现方案
核心思路是先把列转成行(UNPIVOT),再把指定的行转成列(PIVOT),最后单独生成标题行并合并到结果中。这里给出完整的可执行SQL:
WITH UnpivotedData AS ( -- 第一步:把Col1、Col2转成行,得到列名和对应值 SELECT RowNamesCol1, colnames, colvalues FROM PivUnPiv1 UNPIVOT ( colvalues FOR colnames IN (Col1, Col2) ) AS Unpvt ), PivotedValues AS ( -- 第二步:把RowNamesCol1转成列,得到数据行的结构 SELECT colnames AS RowHeader, [Col1Row1], [Col1Row2], [Col1Row3] FROM UnpivotedData PIVOT ( MAX(colvalues) FOR RowNamesCol1 IN ([Col1Row1], [Col1Row2], [Col1Row3]) ) AS Pvt ), HeaderRow AS ( -- 第三步:单独生成第一行的标题行,对应RowNamesCol2的值 SELECT 'RNC1' AS RowHeader, [Col1Row1], [Col1Row2], [Col1Row3] FROM PivUnPiv1 PIVOT ( MAX(RowNamesCol2) FOR RowNamesCol1 IN ([Col1Row1], [Col1Row2], [Col1Row3]) ) AS PvtHeader ) -- 最后合并标题行和数据行,并排序保证顺序 SELECT * FROM HeaderRow UNION ALL SELECT * FROM PivotedValues ORDER BY CASE RowHeader WHEN 'RNC1' THEN 0 ELSE 1 END, RowHeader;
方案解释
- UnpivotedData:将原始表中
Col1和Col2这两列的数值转成行记录,这样我们可以统一处理每一个单元格的值。 - PivotedValues:把
RowNamesCol1的各个值转成列,同时将colnames作为行标题,得到我们需要的数据行部分。 - HeaderRow:专门生成第一行的标题,把每个
RowNamesCol1对应的RowNamesCol2值填充到对应列中,行标题设为RNC1。 - 合并排序:用
UNION ALL把标题行和数据行合并,再通过ORDER BY确保标题行在最顶部,数据行按列名排序。
执行这段SQL后,就能得到你期望的完美结果啦!
内容的提问来源于stack exchange,提问作者KGRed




