【问题标题】:Select column values as columns using PIVOT使用 PIVOT 选择列值作为列
【发布时间】:2013-01-20 10:36:42
【问题描述】:

我有一个场景,我希望将每个唯一列值 (Val2) 的列值 (Val1) 显示为单独的列,最多 10 列。

CREATE TABLE #TEMP1 (Val1 NVARCHAR(4), Val2 NVARCHAR(10));

insert into #Temp1 Values ('S01','00731')
insert into #Temp1 Values ('S02','00731')
insert into #Temp1 Values ('S03','00731')
insert into #Temp1 Values ('S04','00731')
insert into #Temp1 Values ('S05','00731')
insert into #Temp1 Values ('S06','00731')
insert into #Temp1 Values ('S07','00731')
insert into #Temp1 Values ('S08','00731')
insert into #Temp1 Values ('S09','00731')
insert into #Temp1 Values ('S07','00731')
insert into #Temp1 Values ('S04','00741')
insert into #Temp1 Values ('S01','00746')
insert into #Temp1 Values ('S01','00770')
insert into #Temp1 Values ('S01','00771')
insert into #Temp1 Values ('S02','00771')

Val1    Val2
--------------------------
S01     00731
S02     00731
S03     00731
S04     00731
S05     00731
S06     00731
S07     00731
S08     00731
S09     00731
S07     00731
S04     00741
S01     00746
S01     00770
S01     00771
S02     00771

然后我使用一个数据透视列来显示每个唯一的 Val2 值,并使用最多 10 个 Val1 值作为列。

SELECT [Val2],
c1, c2, c3, c4, c5, c6, c7, c8, c9, c10
FROM
(SELECT Val1, Val2
FROM         #TEMP1) AS PivotTable
PIVOT
(
MAX([PivotTable].[Val1])
FOR
Val1
IN
(C1, c2, c3, c4, c5, c6, c7, c8, c9, c10)
) AS PivotTable;

我希望得到如下结果:

Val2    c1  c2  c3  c4  c5  c6  c7  c8  c9  c10
--------------------------------------------------------------------------------------
00731  S01  S02 S03 S04 S05 S06 S07 S08 S09 S07 
00741  S04  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
00746  S01  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
00770  S01  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
00771  S01  S02 NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL

但我实际上只是得到了列的所有 NULL 值:

Val2    c1  c2  c3  c4  c5  c6  c7  c8  c9  c10
--------------------------------------------------------------------------------------
00731  NULL NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
00741  NULL NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
00746  NULL NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
00770  NULL NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
00771  NULL NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL

【问题讨论】:

  • 您误解了PIVOT 的工作原理(这很奇怪,因为您的问题标题似乎正确理解了PIVOT)。数据透视表的列名必须是数据的值。在您说FOR Val1 IN (C1, c2, c3, c4, c5, c6, c7, c8, c9, c10) 的地方,您是说Val1 列具有c1c2 等值,但显然没有,因此您得到NULL
  • 感谢 Lamark,我现在看到了我的错误。在这种情况下,也许枢轴不是我的问题的正确解决方案?您能建议一种方法来达到预期的效果吗?

标签: sql sql-server-2008 tsql pivot


【解决方案1】:

您的要求并不完全清楚,但您似乎正在尝试创建一个名为 c 的新列,然后关联一个 row_number() -- c1, c2 c3, etc

如果您要在子查询中使用以下内容:

SELECT Val1, Val2,
  'C'+ cast(row_number() over(partition by Val2 
                              order by val1) as varchar(10)) col
FROM TEMP1

SQL Fiddle with Demo

你会得到结果:

| VAL1 |  VAL2 | COL |
----------------------
|  S01 | 00731 |  C1 |
|  S02 | 00731 |  C2 |
|  S03 | 00731 |  C3 |
|  S04 | 00731 |  C4 |
|  S05 | 00731 |  C5 |
|  S06 | 00731 |  C6 |
|  S07 | 00731 |  C7 |
|  S07 | 00731 |  C8 |
|  S08 | 00731 |  C9 |
|  S09 | 00731 | C10 |
|  S04 | 00741 |  C1 |
|  S01 | 00746 |  C1 |
|  S01 | 00770 |  C1 |
|  S01 | 00771 |  C1 |
|  S02 | 00771 |  C2 |

这似乎是您想要PIVOT 的结果。然后,您可以使用以下方法将 PIVOT 应用于此:

SELECT Val2,
   c1, c2, c3, c4, c5, c6, c7, c8, c9, c10
FROM
(
  SELECT Val1, Val2,
    'C'+ cast(row_number() over(partition by Val2 
                                order by val1) as varchar(10)) col
  FROM TEMP1
) src
PIVOT
(
  MAX(Val1)
  FOR col IN (C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)
) piv;

SQL Fiddle with Demo。那么你的最终结果是:

|  VAL2 |  C1 |     C2 |     C3 |     C4 |     C5 |     C6 |     C7 |     C8 |     C9 |    C10 |
------------------------------------------------------------------------------------------------
| 00731 | S01 |    S02 |    S03 |    S04 |    S05 |    S06 |    S07 |    S07 |    S08 |    S09 |
| 00741 | S04 | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) |
| 00746 | S01 | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) |
| 00770 | S01 | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) |
| 00771 | S01 |    S02 | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) |

注意:我的结果与您要求的结果略有不同,因为我正在执行 ORDER BY val1,这导致 S07 值被组合在一起。

除非您请求,否则数据库中的数据没有顺序,因此无法保证S07 值之一将显示为C10。您可以使用以下方法获取结果,但不保证结果将始终按正确的顺序排列:

SELECT Val2,
  c1, c2, c3, c4, c5, c6, c7, c8, c9, c10
FROM
(
  SELECT Val1, Val2,
    'C'+ cast(row_number() over(partition by Val2 
                                order by (select 1)) as varchar(10)) col
  FROM TEMP1
) src
PIVOT
(
  MAX(Val1)
  FOR col IN (C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)
) piv;

SQL Fiddle with Demo。使用order by (select 1) 会改变数据的顺序,但它不能保证它总是按那个顺序。结果是:

|  VAL2 |  C1 |     C2 |     C3 |     C4 |     C5 |     C6 |     C7 |     C8 |     C9 |    C10 |
------------------------------------------------------------------------------------------------
| 00731 | S01 |    S02 |    S03 |    S04 |    S05 |    S06 |    S07 |    S08 |    S09 |    S07 |
| 00741 | S04 | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) |
| 00746 | S01 | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) |
| 00770 | S01 | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) |
| 00771 | S01 |    S02 | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) |

【讨论】:

    【解决方案2】:

    您可以尝试使用相关子查询创建交叉表或数据透视表的标准方法,并使用排名函数(在 CTE 中)来确定将值放入哪一列:

    ;with cte as (
        select Val1
            , Val2
            , row_number() over (partition by Val2 order by Val1) as col
            --, row_number() over (partition by Val2 order by Id) as col -- Use this if you have an identity
        from #TEMP1
        --from (select distinct * from #TEMP1) as t -- Use this to rank distinct entries
    )
    select c.Val2
        , (select Val1 from cte where Val2 = c.Val2 and col = 1) as c1
        , (select Val1 from cte where Val2 = c.Val2 and col = 2) as c2
        , (select Val1 from cte where Val2 = c.Val2 and col = 3) as c3
        , (select Val1 from cte where Val2 = c.Val2 and col = 4) as c4
        , (select Val1 from cte where Val2 = c.Val2 and col = 5) as c5
        , (select Val1 from cte where Val2 = c.Val2 and col = 6) as c6
        , (select Val1 from cte where Val2 = c.Val2 and col = 7) as c7
        , (select Val1 from cte where Val2 = c.Val2 and col = 8) as c8
        , (select Val1 from cte where Val2 = c.Val2 and col = 9) as c9
        , (select Val1 from cte where Val2 = c.Val2 and col = 10) as c10
    from cte as c
    group by c.Val2
    order by c.Val2
    

    请注意,有几种方法可以确定 Val2 属于哪个列,我在 CTE 中提出了几种可能性(一些评论)。但是,由于目前无法判断 S07 应该在第十列中,因此无法达到您当前所需的输出。如果您想要的话,也许在临时表中添加一个身份将捕获事件的顺序。我也在 CTE 中包含了这种可能性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-11-18
      • 2011-08-28
      • 2010-11-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-16
      相关资源
      最近更新 更多