2012-09-28 62 views
21

我有一個用戶表動態創建列的sql

Customer ID  Name   
    1    John   
    2    Lewis   
    3    Mary   

我有另一個表CustomerRewards

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

決賽桌

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

的customerTypes表是動態的,很多這些類型可以添加和刪除。基本上所有我想要的是動態生成的列和每一個計數,像

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 

問題就像我說的它的類型是動態的,而且客戶是動態的,所以我需要的列是動態根據在系統

我已標記的C#中的類型,我需要這在一個DataGridView提前

+2

這看起來像一個關鍵。我已經做了一些,但是我無法從記憶中輸入一個。也許在數據庫中創建的視圖是通過在SQL端旋轉數據創建的? –

+1

如果您需要在SQL中執行此操作,您可能需要動態數據透視表。看到,例如,http://www.simple-talk.com/blogs/2007/09/14/pivots-with-dynamic-columns-in-sql-server-2005/但這不是一個乾淨的解決方案。如果您可以等待將數據轉化爲C#,則可以使用LINQ來完成此操作。 –

+0

這些看起來很複雜!感謝您的意見,我會研究Pivot,但如果任何人有一個簡單的解決方案,請隨時 – CR41G14

回答

46

感謝您將要使用PIVOT功能這一點。如果列數已知,則可以對數值進行硬編碼:

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; 

請參閱SQL Fiddle with Demo

現在,如果你有一個未知的列數,那麼你可以使用動態SQL 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) 

SQL Fiddle With Demo

如果您需要包括Total列,那麼你可以使用ROLLUPStatic 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 

動態版(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

優秀的答案! – CR41G14

+1

您有一個SQL注入缺陷/可用性錯誤: = STUFF((SELECT',Sum('+ QUOTENAME(description)+')as'+ description 應該是: = STUFF((SELECT',Sum(' + QUOTENAME(description)+')as'+ QUOTENAME(description) 否則,這是一個很棒的帖子! – shellster

+0

@shellster是的,你說的對。 – Taryn