2013-04-02 23 views
9

ho i seguenti dati di esempio:SQL Server senza aggregato

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

Vorrei mostrare le categorie di una persona appartiene a questo modo:

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

1 e 0 potrebbe essere utilizzato al posto di X e spazi vuoti.

Questo mi fa sembrare una domanda PIVOT.

+0

possibile duplicato del [Get righe come colonne (query SQL PIVOT Dynamic Server) ] (http://stackoverflow.com/questions/12074939/get-rows-as-columns-sql-server-dynamic-pivot-query) – RichardTheKiwi

risposta

25

Esistono diversi modi per trasformare i dati. Alcuni usano una funzione aggregata e altri no. Ma anche se stai ruotando una stringa puoi ancora applicare un aggregato.

aggregata con CASO:

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 

Vedi SQL Fiddle with Demo

Statico Pivot:

è comunque possibile utilizzare la funzione PIVOT di trasformare i dati anche se i valori sono stringhe. Se si dispone di un numero limitato di categorie, allora si può codificare la query:

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 

Vedi SQL Fiddle with Demo.

dinamica Pivot:

Se si dispone di un numero imprecisato di categorie, quindi è possibile utilizzare SQL dinamico:

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) 

Vedi SQL Fiddle with Demo.

più join:

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' 

Vedi SQL Fiddle with Demo

Tutte le query darà il risultato:

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

Heh ... Sono stato wa tching la risposta viene modificata/raffinata. Grazie per aver modificato la risposta per includere il mio requisito che i risultati contengano X/spazi vuoti. Questo si qualifica come la risposta accettata. –

+2

@ BlakeB. Sì si chiama non leggere completamente la domanda, mi dispiace per quello. :) – Taryn

+0

La versione "Aggregate with CASE" di questa soluzione offre prestazioni migliori rispetto alle soluzioni PIVOT. –

Problemi correlati