将行数据透视为列数据而不进行聚合

37

尝试弄清楚如何编写动态的数据透视表 SQL 语句。其中 TEST_NAME 可能有多达 12 种不同的值(因此有 12 列)。其中一些 VAL 将是 Int、Decimal 或 Varchar 数据类型。我看到的大多数示例都包含某种聚合形式。我正在寻找一个直接的值透视。

Source Table 

╔═══════════╦══════╦═══════╗
║ TEST_NAME ║ SBNO ║  VAL  ║
╠═══════════╬══════╬═══════╣
║ Test1     ║    10.304 ║
║ Test1     ║    20.31  ║
║ Test1     ║    30.306 ║
║ Test2     ║    12.3   ║
║ Test2     ║    22.5   ║
║ Test2     ║    32.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  ║
╚══════════════════════════╝
3个回答

54

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

在您的原始问题中,您提到需要将更多的行转换为列。如果是这种情况,您可以使用动态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

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

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

很棒的回答,能否在C#中使用相同的方法? - Oliver
@Oliver 在C#中有一些透视的方法,但我并不是特别熟悉。我建议查看一些关于使用Linq-to-SQL进行透视的SO问题。可以在透视搜索中找到几个相关问题。 - Taryn
1
假设对于特定的SBNO,有多个Test1、Test2和Test3的条目,我能否也将其透视? - sherry

6
没有任何一种方法可以进行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

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

SO15674373 example

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接