2012-09-28 41 views
21

tengo una tabla de Clientescrear dinámicamente columnas sql

Customer ID  Name   
    1    John   
    2    Lewis   
    3    Mary   

tengo otra tabla CustomerRewards

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

y de la mesa final

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

La tabla customerTypes es dinámico, muchos de estos tipos se pueden agregar y eliminar. Básicamente todo lo que quiero es que las columnas se generan de forma dinámica y un recuento en cada uno, algo así como

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 

El problema como he dicho, que los tipos son dinámicos y los clientes son dinámicos por lo que necesitan las columnas a ser dinámico dependiendo de los tipos en el sistema

me han etiquetado como C# necesito esto en un DataGridView

Gracias de antemano

+2

Esto parece un pivote. He hecho algunos, pero no puedo escribir uno de memoria. ¿Tal vez una vista en la base de datos creada a partir de pivotar los datos en el lado de SQL? –

+1

Es probable que desee un pivote dinámico, si necesita hacer esto en SQL. Consulte, por ejemplo, http://www.simple-talk.com/blogs/2007/09/14/pivots-with-dynamic-columns-in-sql-server-2005/. Pero esa no es realmente una solución limpia. Si puede esperar para obtener sus datos en C#, puede usar LINQ para hacer esto. –

+0

¡Estos parecen complejos! gracias por los comentarios, voy a mirar a Pivot, pero si alguien tiene una solución fácil, por favor, siéntase libre – CR41G14

Respuesta

46

Usted tendrá que utilizar una función PIVOT para esto. Si usted tiene un número conocido de columnas, entonces usted puede codificar los valores:

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; 

Ver SQL Fiddle with Demo.

Ahora bien, si usted tiene un número desconocido de columnas, a continuación, puede utilizar SQL dinámico para 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) 

Ver SQL Fiddle With Demo

Si es necesario incluir la columna de la Total, entonces se puede utilizar 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 

versión Dynamic (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

¡Excelente respuesta! – CR41G14

+1

Tienes una inyección SQL defecto/usabilidad de errores: = cosas ((SELECT 'Sum (' + QUOTENAME (descripción) + ') como '+ descripción debe ser: = cosas ((SELECT', Sum (' + QUOTENAME (descripción) + ') como' + QUOTENAME (descripción) De lo contrario, ¡es una publicación increíble! – shellster

+0

@shellster Sí, tienes razón. He actualizado mi código. Gracias por captar eso. – Taryn