2013-08-08 12 views
13

Przepraszam za przesłanie kolejnego pytania na ten temat, ale przeczytałem wiele odpowiedzi na ten temat i nie mogę sprawić, że zadziała to dla mnie.SQL Server 2008 Dane w pionie do Poziomego

Mam trzy tabele, które muszę dołączyć i wyciągnąć informacje. Jedna z tabel ma tylko 3 kolumny i przechowuje dane pionowo. Chciałbym przetransponować te dane do formatu horyzontalnego.

Dane będą wyglądać tak, jeśli tylko przyłączyć i ciągnąć:

SELECT 
    a.app_id, 
    b.field_id, 
    c.field_name, 
    b.field_value 
FROM table1 a 
JOIN table2 b ON a.app_id = b.app_id 
JOIN table3 c ON b.field_id = c.field_id --(table3 is a lookup table for field names) 

Wynik:

app_id | field_id | field_name | field_value 
----------------------------------------------------- 
1234 | 101  | First Name |  Joe 
1234 | 102  |  Last Name |  Smith 
1234 | 105  |  DOB  | 10/15/72 
1234 | 107  | Mailing Addr | PO BOX 1234 
1234 | 110  |  Zip  |  12345  
1239 | 101  | First Name |  Bob 
1239 | 102  |  Last Name |  Johnson 
1239 | 105  |  DOB  | 12/01/78 
1239 | 107  | Mailing Addr | 1234 N Star Ave 
1239 | 110  |  Zip  |  12456 

Zamiast tego chciałbym go wyglądać następująco:

app_id | First Name | Last Name | DOB | Mailing Addr | Zip 
-------------------------------------------------------------------------- 
1234 | Joe  |  Smith  | 10/15/72 | PO BOX 1234 | 12345  
1239 | Bob  | Johnson | 12/01/78 | 1234 N Star Ave | 12456 

W przeszłości, po prostu uciekłem się do sprawdzenia wszystkich danych field_id, których potrzebowałem w moich danych i utworzono instrukcje CASE dla każdego z nich. Aplikacja, z której korzystają użytkownicy, zawiera dane dla wielu produktów, a każdy produkt zawiera inne pola. Biorąc pod uwagę liczbę obsługiwanych produktów i liczbę pól dla każdego produktu (wiele, dużo więcej niż podstawowy przykład, który pokazałem powyżej), trzeba dużo czasu na sprawdzenie i napisanie ogromnych fragmentów instrukcji CASE.

Zastanawiam się, czy istnieje jakiś kod do pobrania, aby osiągnąć to, czego potrzebuję, bez konieczności sprawdzania identyfikatorów field_ids i pisania. Wiem, że funkcja PIVOT jest prawdopodobnie tym, czego szukam, ale nie mogę sprawić, żeby działała poprawnie.

Myślisz, że moglibyście pomóc?

Odpowiedz

29

Można użyć funkcji PIVOT konwertować wierszy danych w kolumnach.

pierwotnym zapytaniu mogą być wykorzystane, aby pobrać wszystkie dane, jedyną zmianą chciałbym zrobić do niego byłoby wykluczyć kolumnę b.field_id ponieważ to zmieni ostateczną wyświetlanie wyniku.

Jeśli masz listę field_name znanej wartości, które chcesz włączyć do kolumn, możesz ciężko kod zapytanie:

select app_id, 
    [First Name], [Last Name], [DOB], 
    [Mailing Addr], [Zip] 
from 
(
    SELECT 
    a.app_id, 
    c.field_name, 
    b.field_value 
    FROM table1 a 
    INNER JOIN table2 b 
    ON a.app_id = b.app_id 
    INNER JOIN table3 c 
    ON b.field_id = c.field_id 
) d 
pivot 
(
    max(field_value) 
    for field_name in ([First Name], [Last Name], [DOB], 
        [Mailing Addr], [Zip]) 
) piv; 

Zobacz SQL Fiddle with Demo.

Ale jeśli masz zamiar mieć nieznaną liczbę wartości dla field_name, następnie trzeba będzie wdrożyć dynamicznego SQL, aby uzyskać wynik:

DECLARE @cols AS NVARCHAR(MAX), 
    @query AS NVARCHAR(MAX) 

select @cols = STUFF((SELECT ',' + QUOTENAME(Field_name) 
        from Table3 
        group by field_name, Field_id 
        order by Field_id 
      FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,'') 

set @query = 'SELECT app_id,' + @cols + ' 
      from 
      (
       SELECT 
       a.app_id, 
       c.field_name, 
       b.field_value 
       FROM table1 a 
       INNER JOIN table2 b 
       ON a.app_id = b.app_id 
       INNER JOIN table3 c 
       ON b.field_id = c.field_id 
      ) x 
      pivot 
      (
       max(field_value) 
       for field_name in (' + @cols + ') 
      ) p ' 

execute sp_executesql @query; 

Zobacz . Oba z nich to da wynik: odpowiedź

| APP_ID | FIRST NAME | LAST NAME |  DOB | MAILING ADDR | ZIP | 
------------------------------------------------------------------------ 
| 1234 |  Joe |  Smith | 10/15/72 |  PO Box 1234 | 12345 | 
| 1239 |  Bob | Johnson | 12/01/78 | 1234 N Star Ave | 12456 | 
+4

To jest dokładnie to, co potrzebne.Nie mam przedstawiciela, który mógłby cię upomnieć, ale jeśli ktokolwiek tutaj widzi to, proszę, upomnij się o mnie! –

3

Spróbuj

SELECT 
    [app_id] 
    ,MAX([First Name]) AS [First Name] 
    ,MAX([Last Name]) AS [Last Name] 
    ,MAX([DOB]) AS [DOB] 
    ,MAX([Mailing Addr]) AS [Mailing Addr] 
    ,MAX([Zip]) AS [Zip] 
FROM Table1 
PIVOT 
(
    MAX([field_value]) FOR [field_name] IN ([First Name],[Last Name],[DOB],[Mailing Addr],[Zip]) 
) T 
GROUP BY [app_id] 

SQL FIDDLE DEMO

0

bluefeet był odpowiedni dla mnie, ale potrzebny odrębny na liście kolumn:

DECLARE @cols AS NVARCHAR(MAX), 
@query AS NVARCHAR(MAX) 

select @cols = STUFF((SELECT Distinct ',' + QUOTENAME(Field_name) 
       from Table3 
       group by field_name, Field_id 
       order by ',' + QUOTENAME(Field_name) 
     FOR XML PATH(''), TYPE 
     ).value('.', 'NVARCHAR(MAX)') 
    ,1,1,'') 

set @query = 'SELECT app_id,' + @cols + ' 
     from 
     (
      SELECT 
      a.app_id, 
      c.field_name, 
      b.field_value 
      FROM table1 a 
      INNER JOIN table2 b 
      ON a.app_id = b.app_id 
      INNER JOIN table3 c 
      ON b.field_id = c.field_id 
     ) x 
     pivot 
     (
      max(field_value) 
      for field_name in (' + @cols + ') 
     ) p ' 

execute sp_executesql @query;