MySQL数据透视表查询与dynamic列
我正在使用下列表格来存储产品数据:
mysql> SELECT * FROM product; +---------------+---------------+--------+ | id | name | description | stock | +---------------+---------------+--------+ | 1 | product1 | first product | 5 | | 2 | product2 | second product| 5 | +---------------+---------------+--------+ mysql> SELECT * FROM product_additional; +-----------------+------------+ | id | fieldname | fieldvalue | +-----------------+------------+ | 1 | size | S | | 1 | height | 103 | | 2 | size | L | | 2 | height | 13 | | 2 | color | black | +-----------------+------------+
使用以下查询从两个表中selectlogging
mysql> SELECT p.id , p.name , p.description ,MAX(IF(pa.fieldname = 'size', pa.fieldvalue, NULL)) as `size` ,MAX(IF(pa.fieldname = 'height', pa.fieldvalue, NULL)) as `height` ,MAX(IF(pa.fieldname = 'color', pa.fieldvalue, NULL)) as `color` FROM product p LEFT JOIN product_additional AS pa ON p.id = pa.id GROUP BY p.id +---------------+---------------+--------+---------+--------+ | id | name | description | size | height | color | +---------------+---------------+--------+---------+--------+ | 1 | product1 | first product | S | 103 | null | | 2 | product2 | second product| L | 13 | black | +---------------+---------------+--------+---------+--------+
一切工作正常:)
因为我dynamic填充“附加”表,这将是很好,如果查询也是dynamic的。 这样,我不必每次更改查询时,我把一个新的字段名和字段值。
MySQL中dynamic执行此操作的唯一方法是使用Prepared语句。 这里有一篇关于他们的好文章:
dynamic数据透视表(将行转换为列)
你的代码看起来像这样:
SET @sql = NULL; SELECT GROUP_CONCAT(DISTINCT CONCAT( 'MAX(IF(pa.fieldname = ''', fieldname, ''', pa.fieldvalue, NULL)) AS ', fieldname ) ) INTO @sql FROM product_additional; SET @sql = CONCAT('SELECT p.id , p.name , p.description, ', @sql, ' FROM product p LEFT JOIN product_additional AS pa ON p.id = pa.id GROUP BY p.id'); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
看演示与SQL小提琴
注:GROUP_CONCAT函数有1024个字符的限制。 请参阅参数group_concat_max_len
我有一个与bluefeet完全不同的方式。 这样,您可以避免使用GROUP_CONCAT,它具有1024个字符的限制,如果您有很多字段,将无法正常工作。
SET @sql = ''; SELECT @sql := CONCAT(@sql,if(@sql='','',', '),temp.output) FROM ( SELECT DISTINCT CONCAT( 'MAX(IF(pa.fieldname = ''', fieldname, ''', pa.fieldvalue, NULL)) AS ', fieldname ) as output FROM product_additional ) as temp; SET @sql = CONCAT('SELECT p.id , p.name , p.description, ', @sql, ' FROM product p LEFT JOIN product_additional AS pa ON p.id = pa.id GROUP BY p.id'); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
这里是存储过程,它将根据一个表和列的数据以及其他表和列的数据生成表。
使用函数'sum(if(col = value,1,0))as value'。 你可以select不同的函数,如MAX(if())等
delimiter // create procedure myPivot( in tableA varchar(255), in columnA varchar(255), in tableB varchar(255), in columnB varchar(255) ) begin set @sql = NULL; set @sql = CONCAT('select group_concat(distinct concat( \'SUM(IF(', columnA, ' = \'\'\',', columnA, ',\'\'\', 1, 0)) AS \'\'\',', columnA, ',\'\'\'\') separator \', \') from ', tableA, ' into @sql'); -- select @sql; PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; -- select @sql; SET @sql = CONCAT('SELECT p.', columnB, ', ', @sql, ' FROM ', tableB, ' p GROUP BY p.', columnB,''); -- select @sql; /* */ PREPARE stmt FROM @sql; EXECUTE stmt; /* */ DEALLOCATE PREPARE stmt; end// delimiter ;