2013-03-28 17 views
14

Versuchen, herauszufinden, wie eine dynamische Pivot-SQL-Anweisung geschrieben wird. Dabei kann TEST_NAME bis zu 12 verschiedene Werte haben (also 12 Spalten haben). Einige der VAL werden Int, Dezimal oder Varchar-Datentypen sein. Die meisten Beispiele, die ich gesehen habe, haben einige von Aggregaten enthalten. Ich suche nach einem geraden Wert Pivot.Pivot-Zeilen zu Spalten ohne Aggregat

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

Antwort

22

Die Funktion PIVOT benötigt eine Aggregation, damit sie funktioniert. Es scheint, dass Ihre VAL Spalte eine varchar ist, so dass Sie entweder die MAX oder MIN Aggregatfunktionen verwenden müssen.

Wenn die Anzahl der Tests beschränkt ist, dann können Sie hartcodieren die Werte:

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; 

Siehe SQL Fiddle with Demo.

In Ihrem OP haben Sie angegeben, dass Sie eine größere Anzahl von Zeilen haben, die in Spalten umgewandelt werden. Wenn das der Fall ist, dann können Sie dynamische SQL verwenden:

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 See.

Beide Versionen werden das gleiche Ergebnis:

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

Große Antwort, ist es möglich, den gleichen Ansatz in C# zu verwenden? – Oliver

+0

@Oliver Es gibt Möglichkeiten, in C# zu schwenken, aber ich kenne sie nicht sehr gut. Ich würde vorschlagen, einige der Fragen zu SO über linq-to-sql mit Pivot zu betrachten. Es gibt mehrere, die in einer Pivot-Suche gefunden werden können. – Taryn

4

Es gibt keinen Weg zu PIVOT ohne zu aggregieren.

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

Eine Abhilfe könnte sein, um sicherzustellen, dass die obligatorische Aggregation wird sich immer nur auf einen einzelnen Datensatz angelegt. In Excel zum Beispiel könnte der Ausgang sein:

SO15674373 example

wo Zeilenbeschriftungen enthalten an der Unterseite eine Spalte von Zellen mit eindeutigen Index-Nummern.