2013-03-28 2 views
14

Пытается понять, как написать динамический сводный sql-оператор. Где TEST_NAME может иметь до 12 различных значений (при этом имеется 12 столбцов). Некоторые из VAL будут типами данных Int, Decimal или Varchar. Большинство примеров, которые я видел, имеют некоторые из включенного агрегата. Я ищу прямую ценность.Поворот строк в столбцы без агрегата

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 ║ 
╚══════════════════════════╝ 

ответ

22

Функция PIVOT требует агрегации, чтобы заставить ее работать. Похоже, что ваш столбец VAL - это varchar, поэтому вам нужно будет использовать либо агрегатные функции , либо MIN.

Если количество тестов ограничено, то вы можете жестко код значения:

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) | 
+0

Отличный ответ, можно ли использовать тот же подход в C#? – Oliver

+0

@Oliver Есть способы поворота на C#, но я не слишком знаком с ними. Я бы предложил посмотреть на некоторые вопросы о SO о linq-to-sql с точкой опоры. Есть несколько, которые можно найти в сводном поиске. – Taryn

4

Нет никакого способа для 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

где метки строк включают в себя в нижнем столбец ячеек с уникальными индексами.

Смежные вопросы