【问题标题】:SQL Server - PIVOT - two columns into rowsSQL Server - PIVOT - 两列成行
【发布时间】:2014-01-21 22:55:23
【问题描述】:

我在一个专栏中看到了许多关于 PIVOT 的问题,每个问题都比其他问题更复杂,但是,我找不到任何我需要的东西。

说实话,我什至不知道在这种情况下 pivot 是否会帮助我。

假设我的源表中有这些数据:

SELECT '1' as 'RowId', 'RandomName1' as 'First', 'RandomLast1' as 'Last'
UNION
SELECT '2' as 'RowId', 'RandomName2' as 'First', 'RandomLast2' as 'Last'
UNION
SELECT '3' as 'RowId', 'RandomName3' as 'First', 'RandomLast3' as 'Last'
UNION
SELECT '4' as 'RowId', 'RandomName4' as 'First', 'RandomLast4' as 'Last'
UNION
SELECT '5' as 'RowId', 'RandomName5' as 'First', 'RandomLast5' as 'Last'

最多 5 行包含名字和姓氏。 First 和 Last 列的值是随机的。

RowId First       Last
----- ----------- -----------
1     RandomName1 RandomLast1
2     RandomName2 RandomLast2
3     RandomName3 RandomLast3
4     RandomName4 RandomLast4
5     RandomName5 RandomLast5

我试图将这些数据转换成这样的东西:

First1      Last1       First2      Last2       First3      Last3       First4      Last4       First5      Last5
----------- ----------- ----------- ----------- ----------- ----------- ----------- ----------- ----------- -----------
RandomName1 RandomLast1 RandomName2 RandomLast2 RandomName3 RandomLast3 RandomName4 RandomLast4 RandomName5 RandomLast5

例如: 如果列 First5 和 Last5 为 NULL,我没有任何问题,因为只有 4 行。

First1      Last1       First2      Last2       First3      Last3       First4      Last4       First5      Last5
----------- ----------- ----------- ----------- ----------- ----------- ----------- ----------- ----------- -----------
RandomName1 RandomLast1 RandomName2 RandomLast2 RandomName3 RandomLast3 RandomName4 RandomLast4 NULL        NULL

谁能给我一点帮助? 谢谢。


基于 Sheela K R 答案的解决方案:

SELECT 
    MAX(First1) as 'First1',  MAX(Last1) as 'Last1',
    MAX(First2) as 'First2',  MAX(Last2) as 'Last2',
    MAX(First3) as 'First3',  MAX(Last3) as 'Last3',
    MAX(First4) as 'First4',  MAX(Last4) as 'Last4',
    MAX(First5) as 'First5',  MAX(Last5) as 'Last5'
FROM
(
    SELECT 
        CASE WHEN RowId = 1 THEN [First] END as 'First1',
        CASE WHEN RowId = 1 THEN [Last] END as 'Last1',
        CASE WHEN RowId = 2 THEN [First] END as 'First2',
        CASE WHEN RowId = 2 THEN [Last] END as 'Last2',
        CASE WHEN RowId = 3 THEN [First] END as 'First3',
        CASE WHEN RowId = 3 THEN [Last] END as 'Last3',
        CASE WHEN RowId = 4 THEN [First] END as 'First4',
        CASE WHEN RowId = 4 THEN [Last] END as 'Last4',
        CASE WHEN RowId = 5 THEN [First] END as 'First5',
        CASE WHEN RowId = 5 THEN [Last] END as 'Last5'
    FROM
    (
        SELECT '1' as 'RowId', 'RandomName1' as 'First', 'RandomLast1' as 'Last'
        UNION SELECT '2' as 'RowId', 'RandomName2' as 'First', 'RandomLast2' as 'Last'
        UNION SELECT '3' as 'RowId', 'RandomName3' as 'First', 'RandomLast3' as 'Last'
        UNION SELECT '4' as 'RowId', 'RandomName4' as 'First', 'RandomLast4' as 'Last'
        --UNION SELECT '5' as 'RowId', 'RandomName5' as 'First', 'RandomLast5' as 'Last'
    ) test
) test2

【问题讨论】:

    标签: sql sql-server sql-server-2012 pivot


    【解决方案1】:

    您可以通过几种不同的方式获得所需的结果。类似于@Sheela K R's 答案,您可以使用带有 CASE 表达式的聚合函数,但可以用更简洁的方式编写:

    select 
      max(case when rowid = 1 then first end) First1,
      max(case when rowid = 1 then last end) Last1,
      max(case when rowid = 2 then first end) First2,
      max(case when rowid = 2 then last end) Last2,
      max(case when rowid = 3 then first end) First3,
      max(case when rowid = 3 then last end) Last3,
      max(case when rowid = 4 then first end) First4,
      max(case when rowid = 4 then last end) Last4,
      max(case when rowid = 5 then first end) First5,
      max(case when rowid = 5 then last end) Last5
    from yourtable;
    

    SQL Fiddle with Demo

    这也可以使用 PIVOT 函数编写,但是由于您要旋转多个列,那么您首先要查看取消旋转 FirstLast 列。

    反透视过程会将您的多列转换为多行数据。您没有指定您使用的 SQL Server 版本,但您可以使用 SELECTUNION ALLCROSS APPLY 甚至 UNPIVOT 函数来执行第一次转换:

    select col = col + cast(rowid as varchar(10)), value
    from yourtable
    cross apply 
    (
      select 'First', First union all
      select 'Last', Last
    ) c (col, value)
    

    SQL Fiddle with Demo。这会将您的数据转换为以下格式:

    |    COL |       VALUE |
    |--------|-------------|
    | First1 | RandomName1 |
    |  Last1 | RandomLast1 |
    | First2 | RandomName2 |
    |  Last2 | RandomLast2 |
    

    一旦数据在多行中,那么您可以轻松地应用 PIVOT 函数:

    select First1, Last1, 
      First2, Last2,
      First3, Last3, 
      First4, Last4, 
      First5, Last5
    from
    (
      select col = col + cast(rowid as varchar(10)), value
      from yourtable
      cross apply 
      (
        select 'First', First union all
        select 'Last', Last
      ) c (col, value)
    ) d
    pivot
    (
      max(value)
      for col in (First1, Last1, First2, Last2,
                  First3, Last3, First4, Last4, First5, Last5)
    ) piv;
    

    SQL Fiddle with Demo

    两者都给出以下结果:

    |      FIRST1 |       LAST1 |      FIRST2 |       LAST2 |      FIRST3 |       LAST3 |      FIRST4 |       LAST4 |      FIRST5 |       LAST5 |
    |-------------|-------------|-------------|-------------|-------------|-------------|-------------|-------------|-------------|-------------|
    | RandomName1 | RandomLast1 | RandomName2 | RandomLast2 | RandomName3 | RandomLast3 | RandomName4 | RandomLast4 | RandomName5 | RandomLast5 |
    

    【讨论】:

    • 你成功了。我喜欢简洁的方式,我使用的是 SQL 2012。
    • @navossoc 简洁的方法肯定更容易,因为你有一个可以使用的rowId
    【解决方案2】:

    试试这样的

    CREATE TABLE #Table1
        ([uid] int, [name] varchar(4), [diseaseid] int, [intensity] varchar(4))
    ;
    
    INSERT INTO #Table1
        ([uid], [name], [diseaseid], [intensity])
    VALUES    (1, 'xxxx', 2, 'low')
        (1, 'xxxx', 1, 'high'),
    
    ;
    
    SELECT MAX([uid]) AS [uid]
           ,MAX([name]) AS [name]
           ,MAX([diseaseid1]) AS [diseaseid1]
           ,MAX([intensity1]) AS [intensity1]
           ,MAX([diseaseid2]) AS [diseaseid2]
           ,MAX([intensity2]) [intensity2]
    FROM 
    (
        SELECT [uid], [name]
        , CASE WHEN rn=2 THEN NULL ELSE [diseaseid] END AS [diseaseid1]
        , CASE WHEN rn=2 THEN NULL ELSE [intensity] END AS [intensity1]
        , CASE WHEN rn=1 THEN NULL ELSE [diseaseid] END AS [diseaseid2]
        , CASE WHEN rn=1 THEN NULL ELSE [intensity] END AS [intensity2]
        FROM
        (
            SELECT [uid], [name], [diseaseid], [intensity], 
            ROW_NUMBER() OVER(PARTITION BY [uid] ORDER BY Name) AS rn
            FROM #Table1
        ) T
    ) T
    GROUP BY [uid], [name]
    

    【讨论】:

    • 不完全是我所需要的,但你的回答帮助了我很多。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2020-07-02
    • 1970-01-01
    • 2021-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多