2012-09-28 7 views
21

Ho una tabella di clientidinamicamente creare colonne sql

Customer ID  Name   
    1    John   
    2    Lewis   
    3    Mary   

ho un altro tavolo CustomerRewards

TypeID   Description 
    1    Bronze 
    2    Silver 
    3    Gold 
    4    Platinum 
    5    AnotherOne 

e il tavolo finale

RewardID   TypeID   CustomerID 
    1    1     1 
    2    1     1 
    3    2     1 
    4    2     2 

La tabella customerTypes è dinamico, molti di questi tipi possono essere aggiunti e rimossi. In pratica tutto quello che voglio è le colonne da generate dinamicamente e un conteggio in ciascuna, qualcosa come

CustomerName  Bronze  Silver  Gold  Platinum  AnotherOne total 
    John    2    1   0   0    0   3 
    Lewis    0    1   0   0    0   1 
Grand TOTAL   2    2   0   0    0   4 

Il problema come ho detto è che i tipi sono dinamici ed i clienti sono dinamici quindi ho bisogno le colonne essere dinamico a seconda dei tipi del sistema

ho etichettato C# come ho bisogno di questo in un DataGridView

Grazie in anticipo

+2

Questo sembra un perno. Ne ho fatte alcune, ma non posso scriverne una dalla memoria. Forse una vista nel DB creata dalla rotazione dei dati sul lato SQL? –

+1

Probabilmente vuoi un pivot dinamico, se devi farlo in SQL. Vedi, ad es. Http://www.simple-talk.com/blogs/2007/09/14/pivots-with-dynamic-columns-in-sql-server-2005/ Ma non è proprio una soluzione pulita. Se puoi aspettare di ottenere i tuoi dati in C#, puoi usare LINQ per farlo. –

+0

Questi sembrano complessi! grazie per i commenti, cercherò su Pivot ma se qualcuno ha una soluzione semplice sentitevi liberi – CR41G14

risposta

46

Si vuole usare una funzione PIVOT per questo. Se si dispone di un numero limitato di colonne, allora si può hard-code dei valori:

select name, [Bronze], [Silver], [Gold], [Platinum], [AnotherOne] 
from 
(
    select c.name, 
    cr.description, 
    r.typeid 
    from customers c 
    left join rewards r 
    on c.id = r.customerid 
    left join customerrewards cr 
    on r.typeid = cr.typeid 
) x 
pivot 
(
    count(typeid) 
    for description in ([Bronze], [Silver], [Gold], [Platinum], [AnotherOne]) 
) p; 

Vedi SQL Fiddle with Demo.

Ora, se si dispone di un numero imprecisato di colonne, quindi è possibile utilizzare SQL dinamico per PIVOT:

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

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

set @query = 'SELECT name,' + @cols + ' from 
      (
       select c.name, 
        cr.description, 
        r.typeid 
       from customers c 
       left join rewards r 
        on c.id = r.customerid 
       left join customerrewards cr 
        on r.typeid = cr.typeid 
      ) x 
      pivot 
      (
       count(typeid) 
       for description in (' + @cols + ') 
      ) p ' 

execute(@query) 

Vedi SQL Fiddle With Demo

Se è necessario includere la colonna Total, quindi è possibile utilizzare ROLLUP (Static Version Demo):

select name, sum([Bronze]) Bronze, sum([Silver]) Silver, 
    sum([Gold]) Gold, sum([Platinum]) Platinum, sum([AnotherOne]) AnotherOne 
from 
(
    select name, [Bronze], [Silver], [Gold], [Platinum], [AnotherOne] 
    from 
    (
    select c.name, 
     cr.description, 
     r.typeid 
    from customers c 
    left join rewards r 
     on c.id = r.customerid 
    left join customerrewards cr 
     on r.typeid = cr.typeid 
) x 
    pivot 
    (
    count(typeid) 
    for description in ([Bronze], [Silver], [Gold], [Platinum], [AnotherOne]) 
) p 
) x 
group by name with rollup 

versione dinamica (Demo):

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

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

select @colsRollup 
     = STUFF((SELECT ', Sum(' + QUOTENAME(description) + ') as '+ QUOTENAME(description) 
        from customerrewards 
        group by description, typeid 
        order by typeid 
      FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,'') 


set @query 
      = 'SELECT name, '+ @colsRollup + ' 
      FROM 
      (
       SELECT name,' + @cols + ' from 
       (
        select c.name, 
         cr.description, 
         r.typeid 
        from customers c 
        left join rewards r 
         on c.id = r.customerid 
        left join customerrewards cr 
         on r.typeid = cr.typeid 
       ) x 
       pivot 
       (
        count(typeid) 
        for description in (' + @cols + ') 
       ) p 
      ) x1 
       GROUP BY name with ROLLUP' 

execute(@query) 
+0

Ottima risposta! – CR41G14

+1

Hai una SQL Injection falla/utilizzabilità bug: = STUFF ((SELECT 'Somma (' + QUOTENAME (descrizione) + '), come '+ descrizione dovrebbe essere: = STUFF ((SELECT', Somma (' + QUOTENAME (descrizione) + ') come' + QUOTENAME (descrizione) Altrimenti, questo è un post fantastico! – shellster

+0

@shellster Sì, hai ragione. Ho aggiornato il mio codice. Grazie per averlo capito. – Taryn