2012-08-17 35 views
48

Digamos que tengo tres tablas diferentes MySQL:MySQL renglón pivote en el número de dinámica de columnas

Tabla products:

id | name 
1 Product A 
2 Product B 

Tabla partners:

id | name 
1 Partner A 
2 Partner B 

tabla sales:

partners_id | products_id 
      1    2 
      2    5 
      1    5 
      1    3 
      1    4 
      1    5 
      2    2 
      2    4 
      2    3 
      1    1 

me gustaría conseguir una mesa con los socios en las filas y columnas como productos. Hasta ahora yo era capaz de obtener una salida como esta:

name  | name  | COUNT(*) 
Partner A Product A   1 
Partner A Product B   1 
Partner A Product C   1 
Partner A Product D   1 
Partner A Product E   2 
Partner B Product B   1 
Partner B Product C   1 
Partner B Product D   1 
Partner B Product E   1 

El uso de esta consulta:

SELECT partners.name, products.name, COUNT(*) 
FROM sales 
JOIN products ON sales.products_id = products.id 
JOIN partners ON sales.partners_id = partners.id 
GROUP BY sales.partners_id, sales.products_id 
LIMIT 0 , 30 

pero me gustaría tener lugar algo así como:

partner_name | Product A | Product B | Product C | Product D | Product E 
Partner A    1   1   1   1   2 
Partner B    0   1   1   1   1 

El problema es que no puedo decir cuántos productos tendré, por lo que el número de columna debe cambiar dinámicamente según las filas en la tabla de productos.

Esta muy buena respuesta no parece trabajar con MySQL: T-SQL Pivot? Possibility of creating table columns from row values

+0

Consulte el enlace [Fila a columna] (https://stackoverflow.com/questions/15745042/efficiently-convert-rows-to-columns-in-sql-server) para obtener múltiples sugerencias. –

Respuesta

70

Desafortunadamente MySQL no tiene una función PIVOT que es básicamente lo que está tratando de hacer. Por lo que tendrá que utilizar una función de agregado con una declaración CASE:

select pt.partner_name, 
    count(case when pd.product_name = 'Product A' THEN 1 END) ProductA, 
    count(case when pd.product_name = 'Product B' THEN 1 END) ProductB, 
    count(case when pd.product_name = 'Product C' THEN 1 END) ProductC, 
    count(case when pd.product_name = 'Product D' THEN 1 END) ProductD, 
    count(case when pd.product_name = 'Product E' THEN 1 END) ProductE 
from partners pt 
left join sales s 
    on pt.part_id = s.partner_id 
left join products pd 
    on s.product_id = pd.prod_id 
group by pt.partner_name 

Ver SQL Fiddle with Demo

Puesto que usted no conoce los productos es probable que desee para realizar esta dinámica. Esto se puede hacer usando declaraciones preparadas.

Dynamic pivot tables (transform rows to columns)

Su código se vería así:

SET @sql = NULL; 
SELECT 
    GROUP_CONCAT(DISTINCT 
    CONCAT(
     'count(case when Product_Name = ''', 
     Product_Name, 
     ''' then 1 end) AS ', 
     replace(Product_Name, ' ', '') 
    ) 
) INTO @sql 
from products; 

SET @sql = CONCAT('SELECT pt.partner_name, ', @sql, ' from partners pt 
left join sales s 
    on pt.part_id = s.partner_id 
left join products pd 
    on s.product_id = pd.prod_id 
group by pt.partner_name'); 

PREPARE stmt FROM @sql; 
EXECUTE stmt; 
DEALLOCATE PREPARE stmt; 

Ver SQL Fiddle with Demo

Es probablemente la pena señalar que GROUP_CONCAT es por defecto limitado a 1024 bytes. Puede evitar esto al establecerlo más alto durante la duración de su procedimiento, es decir. SET @@group_concat_max_len = 32000;

+2

¡El comentario al final con respecto a "max_len" fue un salvavidas! Gracias por el consejo. – Edward

+1

si está buscando consultas dinámicas más dinámicas, consulte esto: http://www.boynux.com/creating-pivot-reports-in-mysql/ – Boynux

Cuestiones relacionadas