2012-09-28 26 views
21

ich eine Tabelle von Kunden habendynamisch erstellen Spalten sql

Customer ID  Name   
    1    John   
    2    Lewis   
    3    Mary   

ich einen anderen Tisch CustomerRewards haben

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

Und der letzte Tisch

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

Die customerTypes Tabelle ist dynamisch, viele Diese Typen können hinzugefügt und entfernt werden. Im Grunde alles, was ich will, ist die Spalten werden dynamisch und eine Zählung in jedem erzeugt, so etwas wie

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 

Das Problem, wie ich sagte ihm, dass die Typen sind dynamisch und die Kunden sind dynamisch, so brauche ich die Spalten dynamisch zu sein abhängig von den Typen im System

I C# markiert haben, wie ich brauche diese in einem Datagridview

Vielen Dank im Voraus

+2

Das sieht wie ein Drehpunkt aus. Ich habe ein paar gemacht, aber ich kann keine aus der Erinnerung eingeben. Vielleicht eine Ansicht in der Datenbank, die durch das Schwenken der Daten auf der SQL-Seite erstellt wurde? –

+1

Wahrscheinlich möchten Sie dynamische Pivot, wenn Sie dies in SQL tun müssen. Siehe z. B. http://www.simple-talk.com/blogs/2007/09/14/pivots-with-dynamic-columns-in-sql-server-2005/ Aber das ist nicht wirklich eine saubere Lösung. Wenn Sie warten können, bis Ihre Daten in C# importiert werden, können Sie dazu LINQ verwenden. –

+0

Diese sehen komplex aus! Danke für die Kommentare, ich werde in Pivot schauen, aber wenn jemand eine einfache Lösung hat, zögern Sie nicht – CR41G14

Antwort

46

Sie erhalten eine PIVOT Funktion für diese verwenden möchten. Wenn Sie eine bekannte Anzahl von Spalten haben, dann können Sie hartcodieren die Werte:

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; 

Siehe SQL Fiddle with Demo.

Nun, wenn Sie eine unbekannte Anzahl von Spalten haben, dann können Sie die dynamische SQL PIVOT verwenden:

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) 

SQL Fiddle With Demo

Siehe Wenn Sie die Total Spalte enthalten müssen, dann können Sie ROLLUP verwenden (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 

Dynamische Version (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

Ausgezeichnete Antwort! – CR41G14

+1

Sie haben einen SQL Injection Fehler/Brauchbarkeit Bug: = STUFF ((SELECT ', Summe (' + QUOTENAME (Beschreibung) + ') als' + Beschreibung Sollte sein: = STUFF ((SELECT ', Summe (') + QUOTENAME (Beschreibung) + ') als' + QUOTENAME (Beschreibung) Sonst ist das ein toller Post! – shellster

+0

@shellster Yup, du hast recht Ich habe meinen Code aktualisiert Danke, dass du ihn geholt hast. – Taryn