2013-04-02 23 views
9

Mam następujące dane przykładowe:SQL Server 2012 PIVOT bez kruszywa

Id Name  Category 
----------------------- 
1  Joe  A 
2  Joe  B 
3  Joe  D 
4  Mary  A 
5  Mary  C 
6  Mary  D 

chciałbym pokazać kategorie dana osoba przynależy do tak: mógłby być stosowany

Name CategoryA CategoryB CategoryC CategoryD 
-------------------------------------------------- 
Joe  X   X      X 
Mary  X      X   X 

1 i 0 zamiast X i blanków.

To pachnie jak pytanie PIVOT do mnie.

+0

możliwe duplikat [Get wiersze w kolumnach (SQL Server dynamiczne PIVOT zapytań) ] (http://stackoverflow.com/questions/12074939/get-rows-as-columns-sql-server-dynamic-pivot-query) – RichardTheKiwi

Odpowiedz

25

Istnieje kilka sposobów przekształcania danych. Niektórzy używają funkcji agregującej, a inni nie. Ale nawet jeśli obracasz łańcuchem, nadal możesz zastosować agregat.

Kruszywo z CASE:

select name, 
    max(case when category = 'A' then 'X' else '' end) CategoryA, 
    max(case when category = 'B' then 'X' else '' end) CategoryB, 
    max(case when category = 'C' then 'X' else '' end) CategoryC, 
    max(case when category = 'D' then 'X' else '' end) CategoryD 
from yourtable 
group by name 

Zobacz SQL Fiddle with Demo

Static Pivot:

Nadal można korzystać z funkcji PIVOT przekształcić dane, mimo że wartości są ciągami. Jeśli masz znaną liczbę kategorii, a następnie można ciężko Kod zapytania:

select name, 
    coalesce(A, '') CategoryA, 
    coalesce(B, '') CategoryB, 
    coalesce(C, '') CategoryC, 
    coalesce(C, '') CategoryD 
from 
(
    select name, category, 'X' flag 
    from yourtable 
) d 
pivot 
(
    max(flag) 
    for category in (A, B, C, D) 
) piv 

Zobacz SQL Fiddle with Demo.

Dynamiczny pivot:

Jeśli masz nieznaną liczbę kategorii, a następnie można użyć dynamicznego SQL:

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

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

select @colsNull = STUFF((SELECT ', coalesce(' + QUOTENAME(category)+', '''') as '+QUOTENAME('Category'+category) 
        from yourtable 
        group by category 
        order by category 
      FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,'') 


set @query = 'SELECT name, ' + @colsNull + ' 
       from 
      (
       select name, category, ''X'' flag 
       from yourtable 
      ) x 
      pivot 
      (
       max(flag) 
       for category in (' + @cols + ') 
      ) p ' 

execute(@query) 

Zobacz SQL Fiddle with Demo.

Multiple przyłącza:

select c1.name, 
    case when c1.category is not null then 'X' else '' end as CategoryA, 
    case when c2.category is not null then 'X' else '' end as CategoryB, 
    case when c3.category is not null then 'X' else '' end as CategoryC, 
    case when c4.category is not null then 'X' else '' end as CategoryD 
from yourtable c1 
left join yourtable c2 
    on c1.name = c2.name 
    and c2.category = 'B' 
left join yourtable c3 
    on c1.name = c3.name 
    and c3.category = 'C' 
left join yourtable c4 
    on c1.name = c4.name 
    and c4.category = 'D' 
where c1.category = 'A' 

Zobacz SQL Fiddle with Demo

wszystkich zapytań dadzą wynik:

| NAME | CATEGORYA | CATEGORYB | CATEGORYC | CATEGORYD | 
-------------------------------------------------------- 
| Joe |   X |   X |   |   X | 
| Mary |   X |   |   X |   X | 
+0

Heh ... Byłem wa Tchnienie odpowiedzi zostanie poddane edycji/dopracowaniu. Dziękuję za edytowanie odpowiedzi w celu uwzględnienia mojego wymogu, że wyniki zawierają X/spacje. To kwalifikuje się jako zaakceptowana odpowiedź. –

+2

@BlakeB. Tak, nazywa się to nie w pełni czytając pytanie, przepraszam za to. :) – Taryn

+0

Okazało się, że wersja tego rozwiązania "Aggregate with CASE" działa znacznie lepiej niż rozwiązania PIVOT. –