具有动态列的MySQL透视表查询

具有动态列的MySQL透视表查询,mysql,dynamic,pivot,Mysql,Dynamic,Pivot,我使用下表存储产品数据: mysql> SELECT * FROM product; +---------------+---------------+--------+ | id | name | description | stock | +---------------+---------------+--------+ | 1 | product1 | first product | 5 | | 2 | product2 | second produc

我使用下表存储产品数据:

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      |
+-----------------+------------+
使用以下查询从两个表中选择记录

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  |
+---------------+---------------+--------+---------+--------+
一切正常:)


因为我动态地填充“附加”表,所以如果查询也是动态的,那就更好了。这样,我就不必每次输入新的字段名和字段值时都更改查询。

在MySQL中,动态执行此操作的唯一方法是使用准备好的语句。下面是一篇关于他们的好文章:

您的代码如下所示:

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, p.name, p.description');

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


注意:GROUP_CONCAT函数的限制为1024个字符。请参见参数组_concat_max_len这里的存储过程,它将根据一个表和列中的数据以及其他表和列中的数据生成表

使用函数“sum(如果(col=value,1,0))作为值”。您可以从不同的函数中进行选择,如MAX(if())等


我的方法与公认的答案略有不同。通过这种方式,您可以避免使用默认限制为1024个字符的GROUP_CONCAT,并且如果有很多字段,除非更改限制,否则将无法使用

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, p.name, p.description');

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

感谢您的快速回答!在PHP中,这意味着我要做两个查询。一个用于获取列字符串,另一个用于将字符串合并到完整查询中?在这里使用Zend Framework。@fr0sty您必须在PHP中测试它。我不确定你将如何处理这段代码。我只是使用了这个例子,并重新应用它从wp_帖子和wp_Posteta中提取数据,这是一个巨大的帮助。非常感谢。我唯一需要添加的是调用设置group_concat_max_len=150000;所以它不会发出警告。这是一个很大的帮助。我将此方法应用于类似的问题,而不是使用SELECT语句,而是每隔几个小时创建一个事件,以重新生成一个视图,该视图将n行从一个表旋转到另一个表的n列中。这是一个很大的帮助,因为在每次执行SELECT之前,我都在使用PHP重建查询。尽管视图不能利用索引,但我认为过滤性能不会成为问题,因为数据透视行->列表示特许经营公司员工接受的培训类型,因此视图不会中断几千行。谢谢@bluefeet@JuanCarlosOropeza感谢您让我知道,我用dbfiddle替换了链接。在mySQL workbench中运行该链接时,我收到了一个错误。怎么跑?对我来说很有效。这将取决于你的错误最终,一个真正的答案!谢谢,事实上,我在
GROUP\u CONCAT
和很多字段上遇到了麻烦。谢谢!!通过定义组连接限制的方式,设置会话组连接最大长度=1000000;上面是为会话集全局组设置的\u concat\u max\u len=1000000@GrumpyCivet您遇到的问题很可能是由于启用了
仅\u FULL\u GROUP\u BY
。简单的解决方案是填充生成查询的GROUPBY子句中的其余列。。。。我现在已经做到了。所以它应该会起作用。这里有一把小提琴在工作
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, p.name, p.description');

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