2013-03-28 11 views
14

Próba obliczenia, jak utworzyć dynamiczne wyrażenie sql sql. Gdzie TEST_NAME może mieć do 12 różnych wartości (tym samym ma 12 kolumn). Niektóre z VAL będą typami danych Int, Decimal lub Varchar. Większość przykładów, które widziałem, zawiera niektóre z agregatów. Szukam prostej osi obrotu.Przenoszenie wierszy do kolumn bez agregatu

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

Odpowiedz

22

Funkcja wymaga agregacji, aby uruchomić. Wygląda na to, że twoja kolumna VAL to varchar, więc będziesz musiał użyć funkcji agregujących MAX lub .

Jeżeli liczba prób jest ograniczona, to można ciężko kod wartości:

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; 

Zobacz SQL Fiddle with Demo.

W twoim PO stwierdziłeś, że będziesz miał większą liczbę wierszy, które zamienią się w kolumny. Jeśli tak jest, to można użyć dynamicznego 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) 

Zobacz SQL Fiddle with Demo.

Obie wersje będą dawać ten sam wynik:

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

Doskonała odpowiedź, czy można użyć tego samego podejścia w języku C#? – Oliver

+0

@Oliver Istnieją sposoby, aby obrócić w C#, ale nie jestem zbyt dobrze z nimi. Proponuję przejrzeć niektóre z pytań na SO dotyczących linq-sql z pivotem. W wyszukiwaniu przestawnym można znaleźć kilka. – Taryn

4

Nie ma żadnego sposobu na PIVOT bez agregowania.

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

Rozwiązaniem może być zapewnienie, że agregacja jest obowiązkowa tylko kiedykolwiek zastosowano do pojedynczego rekordu. Excel na przykład moc może być:

SO15674373 example

gdzie oznaczenia rzędów zawiera w dolnej części kolumny komórek unikalne numery indeksowe.

Powiązane problemy