【问题标题】:PHP MySQL Pivot Table CodePHP MySQL 数据透视表代码
【发布时间】:2015-08-13 14:43:34
【问题描述】:

我已经为 mysql 数据透视表编写了这段代码:

SET @SQL = NULL;
SET @@group_concat_max_len = 6000;
SELECT GROUP_CONCAT( DISTINCT CONCAT( 'MAX(IF(questiondetails = \'', questiondetails, '\', answer, null)) AS \'', questiondetails, '\' ' )) INTO @SQL FROM wtfeedback;
SET @SQL = CONCAT( 'SELECT trialid, productsku, userkey, category, ', @SQL, ' FROM wtfeedback GROUP BY trialid' );
PREPARE stmt FROM @SQL;
EXECUTE stmt;

这在 Sequel Pro(mysql gui 编辑器)中运行良好

但是当我粘贴到我的 php 页面运行此代码时,它显示语法错误:

您的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册,以在 'SET @@group_concat_max_len = 6000; 附近使用正确的语法; SELECT GROUP_CONCAT( DISTINCT CONCAT( 'MAX(I' 在第 3 行

我正在努力查看错误可能是什么。

有什么想法吗?提前致谢。

【问题讨论】:

    标签: php mysql syntax-error pivot pivot-table


    【解决方案1】:

    MySQL 不使用'' 来转义单引号。如果要在 in-sql 字符串中嵌入单引号,请使用 \':

    CONCAT('MAX(IF(questiondetails = \'', questiondetails, '\', answer, null)) AS "', questiondetails, '" ')
                                     ^^---------------------^^
    

    【讨论】:

    • 感谢 Marc,我已按照建议添加了转义字符,但在这一行仍然出现语法错误。 GROUP_CONCAT(DISTINCT CONCAT('MAX(IF(questiondetails = \'', questiondetails, '\', answer, null)) AS "', questiondetails, '" ')) INTO @sql
    【解决方案2】:

    在 PHP 中,一次只发出一个语句。我推断这是问题所在,因为错误指向第二个 SET 的开头。

    Here 是一个存储过程,用于为您生成枢轴 SELECT。

    【讨论】:

      【解决方案3】:

      我和盖伊·默里(Guy Murray)一样在同一个问题上苦苦挣扎,但我还是拼了命。 基本上,我制作了一个存储过程,可以让您在可选的行和列上运行数据透视表,并带有可选的过滤。它首先将“group by”选择查询的结果存储在临时表中,然后使用“group_concat”函数将其放入数据透视表中。和盖伊一样的把戏。 优点是它只遍历主表一次,如果里面有无数条记录,可以节省时间。

      这是一个示例表:

      CREATE TABLE `Data` (
      `Period` INT(2) NOT NULL,
          `Product` VARCHAR(20) NOT NULL DEFAULT '',
          `Amount` DOUBLE NOT NULL
      ) ENGINE=INNODB DEFAULT CHARSET=latin1;
      
      INSERT INTO `Data` (`Period`, `Product`, `Amount`)
      VALUES
          (1,'PrdA',15484),
          (1,'PrdA',45454),
          (1,'PrdB',478),
          (2,'PrdB',985),
          (2,'PrdB',741),
          (2,'PrdB',985),
          (3,'PrdA',7515),
          (3,'PrdA',454),
          (3,'PrdB',4584),
          (2,'PrdB',445),
          (1,'PrdB',669);
      

      这就是存储过程。代码中的附加注释。

      DELIMITER ;;
      CREATE DEFINER=`root`@`localhost` PROCEDURE `pivot`(
          source VARCHAR(1000), 
          val VARCHAR(40), 
          rws VARCHAR(40), 
          cls VARCHAR(40), 
          filter VARCHAR(1000))
      BEGIN
      
      /*
      Creates a pivot table from any table, view or SQL statement. 
      Mandatory: source, value, rows, and columns to be pivoted. 
      Optional filtering.
      
      Sample call strings: 
      CALL pivot('data', 'amount', 'period', 'product', '');
      CALL pivot('(select * from data)', 'amount', 'product', 'period', 'WHERE amount>1000');
      */
      
      
      /*just to be sure*/
      DROP TEMPORARY TABLE IF EXISTS temp1;
      
      /*increase the value of group concat, otherwise the number of columns is very limited*/
      SET SESSION group_concat_max_len = 100000;
      
      /*perform a "select...group by" on the source and store it in a temp table1*/
      SET @a=CONCAT(
          'CREATE TEMPORARY TABLE temp1 (
              SELECT ',
                  rws,' AS rows, ',
                  cls,' AS cols, 
                  SUM(',val,') AS val 
              FROM ',source,' S ',
              filter, ' 
              GROUP BY '
                  ,rws,', ',
                  cls,');'
      );
      
      PREPARE stmt FROM @a;
          EXECUTE stmt;
          DEALLOCATE PREPARE stmt;
      
      /*use "distinct columns" from temp1 to make a text string @coltext, that contains the column statements, to be used in the final step
      Produced text string looks like this:      sum(CASE WHEN cols='PrdA' THEN val END) AS 'PrdA', sum(CASE WHEN cols='PrdB' THEN val END) AS 'PrdB'  */
      SELECT GROUP_CONCAT(
          ' SUM(CASE WHEN cols=\'',cols,'\' THEN val END) AS \'',cols,'\'') 
          INTO @coltext 
      FROM (SELECT DISTINCT(cols) AS cols FROM temp1) A;
      
      /*build the final statement in @b*/
      SET @b=CONCAT(
          'SELECT 
              IFNULL(rows, \'Total\') AS ',rws,', '
              ,@coltext,',
              SUM(val) AS Total 
          FROM temp1 
          GROUP BY 
              rows 
          WITH ROLLUP;');
      
      /*and launch it*/
      PREPARE stmt FROM @b;
          EXECUTE stmt;
          DEALLOCATE PREPARE stmt;
      
      /*clean up*/
      DROP TEMPORARY TABLE IF EXISTS temp1;
      SET @a=NULL;
      SET @b=NULL;
      SET @coltext=NULL;
      
      
      END;;
      DELIMITER ;
      

      结果如下:

       period PrdA    PrdB    total
          1   60938   1147    62085
          2   NULL    3156    3156
          3   7969    4584    12553
       total  68907   8887    77794
      

      希望这会在堆栈溢出时正确显示。这是我在这里的第一篇文章。

      编辑 2015-10-19:在这里阅读其他解决方案时,我意识到可以清理和改进代码:它现在没有任何硬编码引用。只需将其插入任何数据库即可。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-04-08
        • 2020-08-28
        • 2023-03-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多