【问题标题】:How to make awkward pivot of sql table in SQL Server 2005?如何在 SQL Server 2005 中对 sql 表进行尴尬的旋转?
【发布时间】:2011-01-26 20:57:06
【问题描述】:

我必须从 SQL Server 轮换给定的表,但正常的数据透视不起作用(据我尝试)。那么有人知道如何将表格旋转成所需的格式吗?

只是为了使问题更复杂,给定标签的列表可能会有所不同,并且可能会在任何给定时间出现新的标签名称。

给定数据

ID |  Label          |  Numerator  |  Denominator  |  Ratio 
---+-----------------+-------------+---------------+--------
1  |  LabelNameOne   |  41         |  10           |  4,1   
1  |  LabelNameTwo   |  0          |  0            |  0     
1  |  LabelNameThree |  21         |  10           |  2,1   
1  |  LabelNameFour  |  15         |  10           |  1,5   
2  |  LabelNameOne   |  19         |  19           |  1     
2  |  LabelNameTwo   |  0          |  0            |  0     
2  |  LabelNameThree |  15         |  16           |  0,9375
2  |  LabelNameFive  |  19         |  19           |  1     
2  |  LabelNameSix   |  17         |  17           |  1     
3  |  LabelNameOne   |  12         |  12           |  1     
3  |  LabelNameTwo   |  0          |  0            |  0     
3  |  LabelNameThree |  11         |  12           |  0,9167
3  |  LabelNameFour  |  12         |  12           |  1     
3  |  LabelNameSix   |  0          |  1            |  0     

想要的结果

ID | ValueType   | LabelNameOne | LabelNameTwo | LabelNameThree | LabelNameFour | LabelNameFive | LabelNameSix
---+-------------+--------------+--------------+----------------+---------------+---------------+--------------
1  | Numerator   | 41           | 0            | 21             | 15            |               |              
1  | Denominator | 10           | 0            | 10             | 10            |               |              
1  | Ratio       | 4,1          | 0            | 2,1            | 1,5           |               |              
2  | Numerator   | 19           | 0            | 15             |               | 19            | 17           
2  | Denominator | 19           | 0            | 16             |               | 19            | 17           
2  | Ratio       | 1            | 0            | 0,9375         |               | 1             | 1            
3  | Numerator   | 12           | 0            | 11             | 12            |               | 0            
3  | Denominator | 12           | 0            | 12             | 12            |               | 1            
3  | Ratio       | 1            | 0            | 0,9167         | 1             |               | 0            

【问题讨论】:

    标签: sql sql-server sql-server-2005 tsql pivot


    【解决方案1】:

    这应该可以解决您的问题。这真的是一个 UNPIVOT 和一个 PIVOT。请注意,您必须使数据保持一致,因为 UNPIVOT 会将所有数据放在同一列中。

    请注意,我必须在内部动态 SQL 中重新创建/重新填充表变量 - 通常在处理永久表时不需要这样做。

    SET NOCOUNT ON ;
    
    DECLARE @pivot_cols AS varchar(max) ;
    DECLARE @src AS TABLE
        (
         ID int NOT NULL
        ,Label varchar(14) NOT NULL
        ,Numerator int NOT NULL
        ,Denominator int NOT NULL
        ,Ratio decimal(5, 4) NOT NULL
        ) ;
    
    DECLARE @label_order AS TABLE
        (
         Label varchar(14) NOT NULL
        ,Sort int NOT NULL
        )
    
    INSERT  INTO @src
    VALUES  (1, 'LabelNameOne', 41, 10, 4.1) ;
    INSERT  INTO @src
    VALUES  (1, 'LabelNameTwo', 0, 0, 0) ;
    INSERT  INTO @src
    VALUES  (1, 'LabelNameThree', 21, 10, 2.1) ;
    INSERT  INTO @src
    VALUES  (1, 'LabelNameFour', 15, 10, 1.5) ;
    INSERT  INTO @src
    VALUES  (2, 'LabelNameOne', 19, 19, 1) ;
    INSERT  INTO @src
    VALUES  (2, 'LabelNameTwo', 0, 0, 0) ;
    INSERT  INTO @src
    VALUES  (2, 'LabelNameThree', 15, 16, 0.9375) ;
    INSERT  INTO @src
    VALUES  (2, 'LabelNameFive', 19, 19, 1) ;
    INSERT  INTO @src
    VALUES  (2, 'LabelNameSix', 17, 17, 1) ;
    INSERT  INTO @src
    VALUES  (3, 'LabelNameOne', 12, 12, 1) ;
    INSERT  INTO @src
    VALUES  (3, 'LabelNameTwo', 0, 0, 0) ;
    INSERT  INTO @src
    VALUES  (3, 'LabelNameThree', 11, 12, 0.9167) ;
    INSERT  INTO @src
    VALUES  (3, 'LabelNameFour', 12, 12, 1) ;
    INSERT  INTO @src
    VALUES  (3, 'LabelNameSix', 0, 1, 0) ;
    
    INSERT  INTO @label_order
    VALUES  ('LabelNameOne', 1) ;
    INSERT  INTO @label_order
    VALUES  ('LabelNameTwo', 2) ;
    INSERT  INTO @label_order
    VALUES  ('LabelNameThree', 3) ;
    INSERT  INTO @label_order
    VALUES  ('LabelNameFour', 4) ;
    INSERT  INTO @label_order
    VALUES  ('LabelNameFive', 5) ;
    INSERT  INTO @label_order
    VALUES  ('LabelNameSix', 6) ;
    
    WITH    Labels
              AS (
                  SELECT  DISTINCT
                            src.Label
                           ,ISNULL(label_order.Sort, 0) AS Sort
                  FROM      @src AS src
                  LEFT JOIN @label_order AS label_order
                            ON src.label = label_order.label
                 )
        SELECT  @pivot_cols = COALESCE(@pivot_cols + ',', '') + QUOTENAME(Label, '[')
        FROM    Labels
        ORDER BY Sort
               ,Label ;
    
    DECLARE @template AS varchar(max) ;
    
    SET @template = '
    DECLARE @src AS TABLE
        (
         ID int NOT NULL
        ,Label varchar(14) NOT NULL
        ,Numerator int NOT NULL
        ,Denominator int NOT NULL
        ,Ratio decimal(5, 4) NOT NULL
        ) ;
    
    INSERT  INTO @src
    VALUES  (1, ''LabelNameOne'', 41, 10, 4.1) ;
    INSERT  INTO @src
    VALUES  (1, ''LabelNameTwo'', 0, 0, 0) ;
    INSERT  INTO @src
    VALUES  (1, ''LabelNameThree'', 21, 10, 2.1) ;
    INSERT  INTO @src
    VALUES  (1, ''LabelNameFour'', 15, 10, 1.5) ;
    INSERT  INTO @src
    VALUES  (2, ''LabelNameOne'', 19, 19, 1) ;
    INSERT  INTO @src
    VALUES  (2, ''LabelNameTwo'', 0, 0, 0) ;
    INSERT  INTO @src
    VALUES  (2, ''LabelNameThree'', 15, 16, 0.9375) ;
    INSERT  INTO @src
    VALUES  (2, ''LabelNameFive'', 19, 19, 1) ;
    INSERT  INTO @src
    VALUES  (2, ''LabelNameSix'', 17, 17, 1) ;
    INSERT  INTO @src
    VALUES  (3, ''LabelNameOne'', 12, 12, 1) ;
    INSERT  INTO @src
    VALUES  (3, ''LabelNameTwo'', 0, 0, 0) ;
    INSERT  INTO @src
    VALUES  (3, ''LabelNameThree'', 11, 12, 0.9167) ;
    INSERT  INTO @src
    VALUES  (3, ''LabelNameFour'', 12, 12, 1) ;
    INSERT  INTO @src
    VALUES  (3, ''LabelNameSix'', 0, 1, 0) ;
    
    WITH    src_conformed
              AS (
                  SELECT    ID
                           ,Label
                           ,CAST (Numerator AS decimal(10, 4)) AS Numerator
                           ,CAST (Denominator AS decimal(10, 4)) AS Denominator
                           ,CAST (Ratio AS decimal(10, 4)) AS Ratio
                  FROM      @src
                 ),
            UNPIVOTED
              AS (
                  SELECT    *
                  FROM      src_conformed UNPIVOT ( Val FOR Col IN (Numerator, Denominator, Ratio) ) AS unpvt
                 )
        SELECT  *
        FROM    UNPIVOTED PIVOT ( SUM(Val) FOR Label IN ({@pivot_cols}) ) AS pvt
        ORDER BY ID
               ,Col ;' ;
    
    SET @template = REPLACE(@template, '{@pivot_cols}', @pivot_cols) ;
    
    EXEC (@template) ;
    

    【讨论】:

    • 这看起来很棒。即使您将我的测试数据添加为临时表也绝对很棒。如果我能给你比我已经拥有的更多的代表(+1 并标记为正确),我会这样做。万分感谢。
    • 成功使用您的版本后,我只有一个小问题,我无法解决。结果三行的顺序是按字母顺序排列的,但我想在一个 ID 内获得顺序 Num...、Den...、Ratio。任何想法如何得到它?
    • @Oliver 使用我用来制作@label_order 表的相同技术。我注意到了这一点,并认为您会看到我如何解决列顺序并使用相同的技术。
    • 对不起,你是对的。我已经看到了,但是由于我在具体问题中不需要它,这是我删除的第一个问题。当我需要它时,我只是不记得了。
    • @Oliver 没问题 - 此示例代码可能比您系统中所需的代码更长且更复杂,因为您已经拥有所有这些东西的永久表。
    【解决方案2】:
    select
    id,
    'Numerator' as ValueType,
    case when label = labelNameOne then Numerator else 0 end as LabelNameOne,
    case when label = labelNameTwo then Numerator else 0 end as LabelNameTwo,
    case when label = labelNameTree then Numerator else 0 end as LabelNameTree,
    case when label = labelNameFour then Numerator else 0 end as LabelNameFour,
    case when label = labelNameFive then Numerator else 0 end as LabelNameFive,
    case when label = labelNameSix then Numerator else 0 end as LabelNameSix
    
    union All
    

    ...与分母类似的查询...

    union all
    

    ...与比率类似的查询...

    【讨论】:

    • 是的,这是我的尝试之一,但不幸的是标签列表可能会有所不同,因此我无法准确命名案例陈述中的标签。你知道有什么方法可以从select distinct Label from table这样的给定列表中创建案例吗?
    【解决方案3】:

    您寻求的是动态交叉表。简短的回答是,如果没有一些笨拙的动态 SQL,它就无法在 T-SQL 中完成。霍伊尔的回答是,您应该在报告工具或中间层中透视数据。

    【讨论】:

    • 是的,这就是我目前正在运行的方向(在 C++ 中对自己进行操作),但我想,也许有人直接在 SQL 中知道另一种方式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-20
    • 1970-01-01
    • 2018-03-19
    相关资源
    最近更新 更多