【问题标题】:Pivot rows to columns without aggregate将行透视到没有聚合的列
【发布时间】:2013-03-18 10:48:30
【问题描述】:

试图弄清楚如何编写动态数据透视 sql 语句。其中TEST_NAME 最多可以有 12 个不同的值(因此有 12 列)。一些 VAL 将是 Int、Decimal 或 Varchar 数据类型。我见过的大多数示例都包含一些 from of aggregate 。我正在寻找一个直接的价值支点。

Source Table 

╔═══════════╦══════╦═══════╗
║ TEST_NAME ║ SBNO ║  VAL  ║
╠═══════════╬══════╬═══════╣
║ Test1     ║    1 ║ 0.304 ║
║ Test1     ║    2 ║ 0.31  ║
║ Test1     ║    3 ║ 0.306 ║
║ Test2     ║    1 ║ 2.3   ║
║ Test2     ║    2 ║ 2.5   ║
║ Test2     ║    3 ║ 2.4   ║
║ Test3     ║    1 ║ PASS  ║
║ Test3     ║    2 ║ PASS  ║
╚═══════════╩══════╩═══════╝


Desired Output 
╔══════════════════════════╗
║ SBNO Test1 Test2   Test3 ║
╠══════════════════════════╣
║ 1    0.304  2.3    PASS  ║
║ 2    0.31   2.5    PASS  ║
║ 3    0.306  2.4    NULL  ║
╚══════════════════════════╝

【问题讨论】:

    标签: sql pivot


    【解决方案1】:

    PIVOT 函数需要聚合才能使其工作。您的VAL 列似乎是varchar,因此您必须使用MAXMIN 聚合函数。

    如果测试数量有限,那么您可以对值进行硬编码:

    select sbno, Test1, Test2, Test3
    from
    (
      select test_name, sbno, val
      from yourtable
    ) d
    pivot
    (
      max(val)
      for test_name in (Test1, Test2, Test3)
    ) piv;
    

    SQL Fiddle with Demo

    在您的 OP 中,您声明您将有更多的行变成列。如果是这种情况,那么您可以使用动态 SQL:

    DECLARE @cols AS NVARCHAR(MAX),
        @query  AS NVARCHAR(MAX)
    
    select @cols = STUFF((SELECT distinct ',' + QUOTENAME(TEST_NAME) 
                        from yourtable
                FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)') 
            ,1,1,'')
    
    set @query = 'SELECT sbno,' + @cols + '
                 from 
                 (
                    select test_name, sbno, val
                    from yourtable
                ) x
                pivot 
                (
                    max(val)
                    for test_name in (' + @cols + ')
                ) p '
    
    execute(@query)
    

    SQL Fiddle with Demo

    两个版本都会给出相同的结果:

    | SBNO | TEST1 | TEST2 |  TEST3 |
    ---------------------------------
    |    1 | 0.304 |   2.3 |   PASS |
    |    2 |  0.31 |   2.5 |   PASS |
    |    3 | 0.306 |   2.4 | (null) |
    

    【讨论】:

    • 很好的答案,是否可以在 C# 中使用相同的方法?
    • @Oliver 在 C# 中有多种方法可以进行旋转,但我对它们并不太熟悉。我建议在 SO 上查看一些关于 linq-to-sql with pivot 的问题。在数据透视搜索中可以找到几个。
    • 假设某个特定 SBNO 的 Test1、Test2 和 Test3 有多个条目,有没有办法也可以调整它?
    【解决方案2】:

    没有聚合就没有任何方法可以 PIVOT。

    CREATE TABLE #table1
    (
        TEST_NAME VARCHAR(10),
        SBNO VARCHAR(10),
        VAL VARCHAR(10)
    );
    
    INSERT INTO #table1 (TEST_NAME, SBNO, VAL)
    VALUES ('Test1' ,'1', '0.304'),
           ('Test1' ,'2', '0.31'),
           ('Test1' ,'3', '0.306'),
           ('Test2' ,'1', '2.3'),
           ('Test2' ,'2', '2.5'),
           ('Test2' ,'3', '2.4'),
           ('Test3' ,'1', 'PASS'),
           ('Test3' ,'2', 'PASS')
    
    WITH T AS
    (
        SELECT SBNO, VAL, TEST_NAME    
          FROM #table1
    ) 
    SELECT *
      FROM T
     PIVOT (MAX(VAL) FOR TEST_NAME IN([Test1], [Test2], [Test3])) P
    

    【讨论】:

      【解决方案3】:

      一种解决方法可能是确保强制聚合只应用于单个记录。例如,在 Excel 中,输出可能是:

      其中行标签在底部包含一列具有唯一索引号的单元格。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-09-01
        • 2019-03-03
        相关资源
        最近更新 更多