使用MySQL进行动态轴查询

时间:2014-10-09 06:48:08

标签: mysql mysql-workbench

我有下表及详细信息:

示例

 CREATE TABLE Table1
(`PK` int, `Name` varchar(3), `Subject` varchar(9), `Grade` varchar(1));

INSERT INTO Table1
(`PK`, `Name`, `Subject`, `Grade`)
VALUES
(1, 'Bob', 'Math', 'A'),
(2, 'Bob', 'History', 'B'),
(3, 'Bob', 'Language', 'C'),
(4, 'Bob', 'Biology', 'D'),
(5, 'Sue', 'History', 'C'),
(6, 'Sue', 'Math', 'A'),
(7, 'Sue', 'Music', 'A'),
(8, 'Sue', 'Geography', 'C');

现在我想编写一个存储过程,我希望通过该过程来转动表。

尝试

 DELIMITER $$
 create PROCEDURE sptest1(IN nm varchar(50),IN sub varchar(50))
 begin
 SET @sql = NULL;

 SELECT GROUP_CONCAT(DISTINCT
     CONCAT('MAX(CASE WHEN ', nm ,' = ''', nm,
     ''' THEN grade END) `', nm, '`'))
 INTO @sql
 FROM table1;

 SET @sql = CONCAT('SELECT ', sub ,',', @sql, ' 
                 FROM table1 
                GROUP BY ', sub ,'');
select @sql;
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

END$$
DELIMITER ;

调用功能:

call sptest1('name','subject')

但结果错了:

 subject    name
 ----------------
 Biology    null
 Geography  null
 History    null
 Language   null
 Math       null
 Music      null

预期结果:

 subject    Bob     Sue
 -------------------------
 Biology    D       null    
 Geography  null    C
 History    B       C
 Language   C       null
 Math       A       A
 Music      null    A

1 个答案:

答案 0 :(得分:1)

您可以将动态sql查询重写为

SET @sql = NULL;
SELECT GROUP_CONCAT( DISTINCT
  CONCAT('MAX(CASE WHEN `Name` = ''',
         `Name`, 
         ''' THEN grade END) ',
         `Name`)  
         )
  INTO @sql
  FROM table1;
SET @sql = CONCAT('SELECT `Subject`, ', @sql, ' FROM table1 GROUP BY `Subject`');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

Demo

在您的存储过程中,如果您将其作为参数传递,则必须为动态sql硬编码您的名称列,然后您可以使用大小写来检查列,例如

MAX(CASE WHEN ', nm ,' = ''', nm, ..

上述部分程序将评估为MAX(CASE WHEN name = 'name' ..,因为变量nm包含“名称”,它不会将其识别为列

DROP PROCEDURE `sptest1`; 
DELIMITER $$
CREATE
    PROCEDURE `sib`.`sptest1`(IN nm VARCHAR(50),IN sub VARCHAR(50))
    BEGIN
SET @sql = NULL;
SELECT GROUP_CONCAT( DISTINCT
   CONCAT('MAX(CASE WHEN ',nm,' = ''',CASE WHEN nm = 'name' THEN `Name` END,''' THEN grade END) ',CASE WHEN nm = 'name' THEN `Name` END)
  )
  INTO @sql
  FROM table1;
SET @sql = CONCAT('SELECT ', sub ,',', @sql, '  FROM table1 GROUP BY ', sub ,'');
/*select @sql; */
 PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END$$
DELIMITER ;

Demo