[MySQL] 行列變化各種方法實現總結(行變列報表統計、列變行資料記錄統計等)

dbasdk發表於2014-09-10

 前言:

mysql行列變化,最難的就是將多個列變成多行,使用的比較多的是統計學中行變列,列變行,沒有找到現成的函式或者語句,所以自己寫了儲存過程,使用動態sql來實現,應用業務場景,使用者每個月都有使用記錄數錄入一張表,一個月一個欄位,所以表的欄位是動態增長的,現在需要實時統計當前使用者使用的總數量,如果你知道有多少個欄位,那麼可以用select c1+c2+c3+…. From tbname where tid=’111’;來實現,但是關鍵是這個都是動態的,所以在應用程式端來實現確實不適宜,可以放在資料庫後臺在儲存過程裡實現。

 

而且在行變成列中,如果要寫單個sql來實現,列的數目就需要寫死,因為如果不知道要展示成多少列的話,就需要用動態變數,而一條sql裡面無法使用動態變數。但是可以使用sql塊來實現動態的效果。
  

一,列變成行例子演示

1,準備測試資料

這是基礎資料表,裡面有多個欄位wm201403……,現在需要把N個這樣的列變成行資料。

  1. USE csdn;
  2. DROP TABLE IF EXISTS flow_table;
  3. CREATE TABLE `flow_table` (
  4.   `ID` INT(11) NOT NULL AUTO_INCREMENT,
  5.   `Number` BIGINT(11) NOT NULL,
  6.   `City` VARCHAR(10) NOT NULL,
  7.   `wm201403` DECIMAL(7,2) DEFAULT NULL,
  8.   `wm201404` DECIMAL(7,2) DEFAULT NULL,
  9.   `wm201405` DECIMAL(7,2) DEFAULT NULL,
  10.   `wm201406` DECIMAL(7,2) DEFAULT NULL,
  11.   `wm201407` DECIMAL(7,2) DEFAULT NULL,
  12.   `wm201408` DECIMAL(7,2) DEFAULT NULL,
  13.   PRIMARY KEY (`ID`,`Number`)
  14. ) ENGINE=INNODB DEFAULT CHARSET=utf8;

錄入一批測試資料:

  1. INSERT INTO flow_table(Number,City,wm201403,wm201404,wm201405,wm201406,wm201407,wm201408)SELECT 1,\'shanghai\',100.2,180.4,141,164,124,127;
  2. INSERT INTO flow_table(Number,City,wm201403,wm201404,wm201405,wm201406,wm201407,wm201408)SELECT 2,\'shanghai\',110.23,180.34,141.23,104.78,124.67,127.45;
  3. INSERT INTO flow_table(Number,City,wm201403,wm201404,wm201405,wm201406,wm201407,wm201408)SELECT 3,\'beijing\',123.23,110.34,131.33,154.58,154.67,167.45;
  4. INSERT INTO flow_table(Number,City,wm201403,wm201404,wm201405,wm201406,wm201407,wm201408)SELECT 4,\'hangzhou\',0,110.34,131.33,154.58,154.67,0;
  5. INSERT INTO flow_table(Number,City,wm201405,wm201406,wm201407,wm201408)SELECT 5,\'hangzhou\',131.33,154.58,154.67,0;

需要達到的統計效果是:

+--------+-----------+

| Number | total_num |

+--------+-----------+

|      1 |    836.60 |

|      2 |    788.70 |

|      3 |    841.60 |

|      4 |    550.92 |

|      5 |    440.58 |

+--------+-----------+

5 rows in set (0.00 sec)


2,儲存過程遍歷:

這個儲存過程建立了2張臨時表,查詢測試表資料形成遊標,遍歷遊標根據主鍵Number來呼叫pro_flow_modify儲存過程進行行列變化。程式碼如下:

  1. DELIMITER $$
  2. DROP PROCEDURE IF EXISTS csdn.`proc_all_changes`$$
  3. CREATE PROCEDURE csdn.proc_all_changes()
  4. BEGIN
  5.     DECLARE v_number BIGINT;
  6.     DECLARE v_city VARCHAR(10);
  7.     DECLARE _done INT DEFAULT 0;
  8.    
  9.     /*定義遊標*/
  10.     DECLARE cur_all CURSOR FOR SELECT Number,City FROM csdn.`flow_table`;
  11.     /**這裡如果需要定義下當NOT FOUND的時候,EXIT退出遊標遍歷,不然如果設定成CONTINUE會一直執行下去。*/
  12.     DECLARE EXIT HANDLER FOR NOT FOUND BEGIN SET _done=1;END;
  13.    
  14.        /*建立臨時表,存放所有欄位的臨時表*/
  15.          DROP TABLE IF EXISTS flow_n_columns;
  16.          CREATE TABLE `flow_n_columns` (
  17.            `column_name` VARCHAR(10) NOT NULL
  18.          ) ENGINE=INNODB DEFAULT CHARSET=utf8;
  19.  
  20.          /*存放最終變成行的資料表*/
  21.          DROP TABLE IF EXISTS flow_tmp;
  22.          CREATE TABLE `flow_tmp` (
  23.            `Number` INT(11) DEFAULT NULL,
  24.            `City` VARCHAR(10) DEFAULT NULL,
  25.            `wm_str` VARCHAR(10) DEFAULT NULL,
  26.            `Wm` DECIMAL(7,2) DEFAULT NULL
  27.          ) ENGINE=INNODB DEFAULT CHARSET=utf8;
  28.  
  29.     OPEN cur_all;
  30.     REPEAT
  31.         FETCH cur_all INTO v_number, v_city;
  32.         IF NOT _done THEN
  33.                    CALL csdn.pro_flow_modify(v_number,v_city);
  34.         END IF;
  35.         UNTIL _done=1 END REPEAT;
  36.     CLOSE cur_all;
  37.              /*展示下所有的行轉列的資料**/
  38.          SELECT * FROM csdn.flow_tmp;
  39. END$$
  40. DELIMITER ;


3,行裡變化儲存過程

透過查詢系統表information_schema.`COLUMNS`來獲取測試表flow_table的所有列,然後寫動態SQL,來把列的值錄入到臨時表flow_tmp中。

  1. DELIMITER $$
  2. DROP PROCEDURE IF EXISTS csdn.`pro_flow_modify`$$
  3. CREATE PROCEDURE csdn.`pro_flow_modify`(p_Number INT,p_city VARCHAR(10))
  4. BEGIN
  5.          DECLARE v_column_name VARCHAR(10) DEFAULT \'\';
  6.          DECLARE v_exe_sql VARCHAR(1000) DEFAULT \'\';
  7.          DECLARE v_start_wm VARCHAR(10) DEFAULT \'\';
  8.          DECLARE v_end_wm VARCHAR(10) DEFAULT \'\';
  9.          DECLARE v_num DECIMAL(10,2) DEFAULT 0;
  10.         
  11.          DECLARE i INT DEFAULT 1;
  12.          DECLARE v_Number INT DEFAULT 0;
  13.          SET v_Number=p_Number;
  14.         
  15.          DELETE FROM csdn.flow_n_columns;
  16.          DELETE FROM csdn.flow_tmp WHERE Number=v_Number;
  17.         
  18.         
  19.          /*把測試表flow_table的所有欄位都錄入欄位臨時表中,這樣就達到了從列變成行的目的*/
  20.          INSERT INTO flow_n_columns
  21.          SELECT t.`COLUMN_NAME` FROM information_schema.`COLUMNS` t WHERE t.`TABLE_NAME`=\'flow_table\' AND t.`TABLE_SCHEMA`=\'csdn\' AND t.`COLUMN_NAME` NOT IN(\'ID\',\'Number\',\'City\');
  22.          SELECT column_name INTO v_column_name FROM csdn.flow_n_columns LIMIT 1;
  23.         
  24.          /*開始迴圈遍歷欄位臨時表的欄位資料,並且把欄位值放入臨時表flow_tmp裡面*/
  25.          WHILE i>0 DO
  26.                    SET v_exe_sql=CONCAT(\'INSERT INTO csdn.flow_tmp(Number,City,wm_str,Wm) select \',v_Number,\',\\\'\',p_city, \'\\\',\\\'\',v_column_name,\'\\\',\',v_column_name,\' from csdn.flow_table WHERE flow_table.Number=\',v_Number,\';\');
  27.                    SET @sql=v_exe_sql;
  28.                    PREPARE s1 FROM @sql;
  29.                    EXECUTE s1;
  30.                    DEALLOCATE PREPARE s1;
  31.                    DELETE FROM csdn.flow_n_columns WHERE column_name=v_column_name;
  32.                    SELECT column_name INTO v_column_name FROM csdn.flow_n_columns LIMIT 1;
  33.                    SELECT COUNT(1) INTO i FROM csdn.flow_n_columns ;
  34.                    DELETE FROM csdn.flow_tmp WHERE Wm=0;
  35.          END WHILE;
  36.  
  37.          /*由於觸發器是不支援動態sql,所以不能使用while迴圈,動態遍歷所有統計列的,只能寫死列了,如下所示:
  38.          現在一個個insert只能寫死了, flow_table表有多少個統計列就寫多少個insert sql,以後新新增一個列,就在這裡新新增一條insertsql語句
  39.          INSERT INTO flow_tmp(Number,City,wm_str,Wm) SELECT v_Number,p_city,\'wm201403\',wm201403 FROM flow_table WHERE Number=v_Number ;
  40.          INSERT INTO flow_tmp(Number,City,wm_str,Wm) SELECT v_Number,p_city,\'wm201404\',wm201404 FROM flow_table WHERE Number=v_Number ;
  41.          INSERT INTO flow_tmp(Number,City,wm_str,Wm) SELECT v_Number,p_city,\'wm201405\',wm201405 FROM flow_table WHERE Number=v_Number ;
  42.          INSERT INTO flow_tmp(Number,City,wm_str,Wm) SELECT v_Number,p_city,\'wm201406\',wm201406 FROM flow_table WHERE Number=v_Number ;
  43.          INSERT INTO flow_tmp(Number,City,wm_str,Wm) SELECT v_Number,p_city,\'wm201407\',wm201407 FROM flow_table WHERE Number=v_Number ;
  44.          INSERT INTO flow_tmp(Number,City,wm_str,Wm) SELECT v_Number,p_city,\'wm201408\',wm201408 FROM flow_table WHERE Number=v_Number ;
  45.          */
  46.         
  47.          /*清除掉不資料=0的列*/
  48.          DELETE FROM csdn.flow_tmp WHERE Wm=0 OR Wm IS NULL;
  49.         
  50.          SELECT wm_str INTO v_start_wm FROM csdn.flow_tmp WHERE Number=v_Number ORDER BY wm_str ASC LIMIT 1;
  51.          SELECT wm_str INTO v_end_wm FROM csdn.flow_tmp WHERE Number=v_Number ORDER BY wm_str DESC LIMIT 1;
  52.          SELECT SUM(Wm) INTO v_num FROM csdn.flow_tmp WHERE Number=v_Number;
  53.         
  54.  
  55.     END$$
  56.  
  57. DELIMITER ;

4,列變行結果展示

臨時表的所有資料:

  1. mysql> SELECT * FROM csdn.flow_tmp;
  2. +--------+----------+----------+--------+
  3. | Number | City | wm_str | Wm |
  4. +--------+----------+----------+--------+
  5. | 1 | shanghai | wm201403 | 100.20 |
  6. | 1 | shanghai | wm201404 | 180.40 |
  7. | 1 | shanghai | wm201405 | 141.00 |
  8. | 1 | shanghai | wm201406 | 164.00 |
  9. | 1 | shanghai | wm201407 | 124.00 |
  10. | 1 | shanghai | wm201408 | 127.00 |
  11. | 2 | shanghai | wm201403 | 110.23 |
  12. | 2 | shanghai | wm201404 | 180.34 |
  13. | 2 | shanghai | wm201405 | 141.23 |
  14. | 2 | shanghai | wm201406 | 104.78 |
  15. | 2 | shanghai | wm201407 | 124.67 |
  16. | 2 | shanghai | wm201408 | 127.45 |
  17. | 3 | beijing | wm201403 | 123.23 |
  18. | 3 | beijing | wm201404 | 110.34 |
  19. | 3 | beijing | wm201405 | 131.33 |
  20. | 3 | beijing | wm201406 | 154.58 |
  21. | 3 | beijing | wm201407 | 154.67 |
  22. | 3 | beijing | wm201408 | 167.45 |
  23. | 4 | hangzhou | wm201404 | 110.34 |
  24. | 4 | hangzhou | wm201405 | 131.33 |
  25. | 4 | hangzhou | wm201406 | 154.58 |
  26. | 4 | hangzhou | wm201407 | 154.67 |
  27. | 5 | hangzhou | wm201405 | 131.33 |
  28. | 5 | hangzhou | wm201406 | 154.58 |
  29. | 5 | hangzhou | wm201407 | 154.67 |
  30. +--------+----------+----------+--------+
  31. 25 rows in set (0.00 sec)
  32. mysql>

統計每個使用者的使用總量為:

  1. mysql> SELECT Number,SUM(Wm) \'total_num\' FROM flow_tmp GROUP BY Number ORDER BY Number;
  2. +--------+-----------+
  3. | Number | total_num |
  4. +--------+-----------+
  5. | 1 | 836.60 |
  6. | 2 | 788.70 |
  7. | 3 | 841.60 |
  8. | 4 | 550.92 |
  9. | 5 | 440.58 |
  10. +--------+-----------+
  11. 5 rows in set (0.00 sec)
  12.  
  13. mysql>
 

二,行變列例子演示

1,準備測試資料

  1. USE csdn;
  2. DROP TABLE IF EXISTS csdn.tb;
  3. CREATE TABLE tb(`cname` VARCHAR(10),cource VARCHAR(10),score INT) ENGINE=INNODB;
  4. INSERT INTO tb VALUES(\'張三\',\'語文\',74);
  5. INSERT INTO tb VALUES(\'張三\',\'數學\',83);
  6. INSERT INTO tb VALUES(\'張三\',\'物理\',93);
  7. INSERT INTO tb VALUES(\'李四\',\'語文\',74);
  8. INSERT INTO tb VALUES(\'李四\',\'數學\',84);
  9. INSERT INTO tb VALUES(\'李四\',\'物理\',94);

需要得到的結果是:

+--------------------+--------+--------+--------+-----------+--------------+

| 姓名               | 語文   | 數學   | 物理   | 總成績    | 平均成績     |

+--------------------+--------+--------+--------+-----------+--------------+

| 張三               |  74.00 |  83.00 |  93.00 |    250.00 |        83.33 |

| 李四               |  74.00 |  84.00 |  94.00 |    252.00 |        84.00 |

| 總成績平均數       |  74.00 |  83.50 |  93.50 |    251.00 |        83.67 |

+--------------------+--------+--------+--------+-----------+--------------+

 

2,利用SUM(IF()) 生成列 + WITH ROLLUP 生成彙總行,並利用 IFNULL將彙總行標題顯示為 Total_num

SQL程式碼塊如下:

  1. SELECT cname AS \"姓名\",
  2.          SUM(IF(cource=\"語文\",score,0)) AS \"語文\",
  3.          SUM(IF(cource=\"數學\",score,0)) AS \"數學\",
  4.          SUM(IF(cource=\"物理\",score,0)) AS \"物理\",
  5.          SUM(score) AS \"總成績\",
  6.          ROUND(AVG(score),2) AS \"平均成績\"
  7. FROM tb
  8. GROUP BY cname
  9. UNION ALL
  10. SELECT
  11.          \"總成績平均數\",
  12.          ROUND(AVG(`語文`),2) , ROUND(AVG(`數學`),2), ROUND(AVG(`物理`),2), ROUND(AVG(`總成績`),2), ROUND(AVG(`平均成績`),2)
  13. FROM(
  14.          SELECT \"all\",cname AS \"姓名\",
  15.                    SUM(IF(cource=\"語文\",score,0)) AS \"語文\",
  16.                    SUM(IF(cource=\"數學\",score,0)) AS \"數學\",
  17.                    SUM(IF(cource=\"物理\",score,0)) AS \"物理\",
  18.                    SUM(score) AS \"總成績\",
  19.                    AVG(score) AS \"平均成績\"
  20.          FROM tb
  21.          GROUP BY cname
  22. )tb2
  23. GROUP BY tb2.all;

執行結果正確,如下所示:

+--------------------+--------+--------+--------+-----------+--------------+

| 姓名               | 語文   | 數學   | 物理   | 總成績    | 平均成績     |

+--------------------+--------+--------+--------+-----------+--------------+

| 張三               |  74.00 |  83.00 |  93.00 |    250.00 |        83.33 |

| 李四               |  74.00 |  84.00 |  94.00 |    252.00 |        84.00 |

| 總成績平均數       |  74.00 |  83.50 |  93.50 |    251.00 |        83.67 |

+--------------------+--------+--------+--------+-----------+--------------+

 

3,利用max(CASE ... WHEN ... THEN .. ELSE END) AS "語文"的方式來實現

 SQL程式碼如下:

  1. SELECT
  2.          cname AS \"姓名\",
  3.          MAX(CASE cource WHEN \"語文\" THEN score ELSE 0 END) AS \"語文\",
  4.          MAX(CASE cource WHEN \"數學\" THEN score ELSE 0 END) AS \"數學\",
  5.          MAX(CASE cource WHEN \"物理\" THEN score ELSE 0 END) AS \"物理\",
  6.          SUM(score) AS \"總成績\",
  7.          ROUND(AVG(score) ,2) AS \"平均成績\"
  8. FROM tb
  9. GROUP BY `cname`
  10. UNION ALL
  11. SELECT
  12.          \"總成績平均數\",
  13.          ROUND(AVG(`語文`),2) , ROUND(AVG(`數學`),2), ROUND(AVG(`物理`),2), ROUND(AVG(`總成績`),2), ROUND(AVG(`平均成績`),2)
  14. FROM( SELECT \'all\' ,
  15.                    cname AS \"姓名\",
  16.                    MAX(CASE cource WHEN \"語文\" THEN score ELSE 0 END) AS \"語文\",
  17.                    MAX(CASE cource WHEN \"數學\" THEN score ELSE 0 END) AS \"數學\",
  18.                    MAX(CASE cource WHEN \"物理\" THEN score ELSE 0 END) AS \"物理\",
  19.                    SUM(score) AS \"總成績\",
  20.                    ROUND(AVG(score) ,2) AS \"平均成績\"
  21.          FROM tb
  22.          GROUP BY `cname`
  23. )tb2 GROUP BY tb2.all

執行結果正確,如下所示:

+--------------------+--------+--------+--------+-----------+--------------+

| 姓名               | 語文   | 數學   | 物理   | 總成績    | 平均成績     |

+--------------------+--------+--------+--------+-----------+--------------+

| 張三               |  74.00 |  83.00 |  93.00 |    250.00 |        83.33 |

| 李四               |  74.00 |  84.00 |  94.00 |    252.00 |        84.00 |

| 總成績平均數       |  74.00 |  83.50 |  93.50 |    251.00 |        83.67 |

+--------------------+--------+--------+--------+-----------+--------------+

 

4,利用 WITH rollup結果不符合

SQL程式碼如下:


  1. SELECT IFNULL(cname,\'總平均數\') AS \"姓名\",
  2.          MAX(CASE cource WHEN \"語文\" THEN score ELSE 0 END) AS \"語文\",
  3.          MAX(CASE cource WHEN \"數學\" THEN score ELSE 0 END) AS \"數學\",
  4.          MAX(CASE cource WHEN \"物理\" THEN score ELSE 0 END) AS \"物理\",
  5.          ROUND(AVG(score),2) AS \"總成績\",
  6.          ROUND(AVG(avg_score),2) AS \"平均成績\"
  7.     FROM(
  8.          SELECT
  9.                    cname ,
  10.                    IFNULL(cource,\'total\') cource,
  11.                    SUM(score) AS score,
  12.                    ROUND(AVG(score) ,2) AS avg_score
  13.          FROM tb
  14.          GROUP BY `cname`,cource WITH ROLLUP HAVING cname IS NOT NULL
  15.          )tb2
  16.          GROUP BY tb2.cname WITH ROLLUP;


執行結果不對,總平均數欄目,裡面各科比較語文數學的班級平均數不對,如下所示:

  1. mysql> SELECT IFNULL(cname,\'總平均數\') AS \"姓名\",
  2.     -> MAX(CASE cource WHEN \"語文\" THEN score ELSE 0 END) AS \"語文\",
  3.     -> MAX(CASE cource WHEN \"數學\" THEN score ELSE 0 END) AS \"數學\",
  4.     -> MAX(CASE cource WHEN \"物理\" THEN score ELSE 0 END) AS \"物理\",
  5.     -> ROUND(AVG(score),2) AS \"總成績\",
  6.     -> ROUND(AVG(avg_score),2) AS \"平均成績\"
  7.     -> FROM(
  8.     -> SELECT
  9.     ->
  10. Display ALL 793 possibilities? (Y OR n)
  11.     -> cname ,
  12.     ->
  13. Display ALL 793 possibilities? (Y OR n)
  14.     -> IFNULL(cource,\'total\') cource,
  15.     ->
  16. Display ALL 793 possibilities? (Y OR n)
  17.     -> SUM(score) AS score,
  18.     ->
  19. Display ALL 793 possibilities? (Y OR n)
  20.     -> ROUND(AVG(score) ,2) AS avg_score
  21.     -> FROM tb
  22.     -> GROUP BY `cname`,cource WITH ROLLUP HAVING cname IS NOT NULL
  23.     -> )tb2
  24.     -> GROUP BY tb2.cname WITH ROLLUP;
  25. +--------------+--------+--------+--------+-----------+--------------+
  26. | 姓名 | 語文 | 數學 | 物理 | 總成績 | 平均成績 |
  27. +--------------+--------+--------+--------+-----------+--------------+
  28. | 張三 | 74 | 83 | 93 | 125.00 | 83.33 |
  29. | 李四 | 74 | 84 | 94 | 126.00 | 84.00 |
  30. | 總平均數 | 74 | 84 | 94 | 125.50 | 83.67 |
  31. +--------------+--------+--------+--------+-----------+--------------+
  32. 3 ROWS IN SET, 1 warning (0.00 sec)
  33.  
  34. mysql>

總結: WITH rollup中對求列的總數是OK的,但是求列的平均數有偏差,這裡場景使用不是恰當。


5,使用動態SQL來實現

SQL程式碼塊如下:

  1. /*僅僅班級成員部分*/
  2. SET @a=\'\';
  3. SELECT @a:=CONCAT(@a,\'SUM(IF(cource=\\\'\',cource,\'\\\'\',\',score,0)) AS \',cource,\',\') FROM (SELECT DISTINCT cource FROM tb) A;
  4. SET @a=CONCAT(@a,\"ROUND(AVG(score) ,2) AS \\\"平均成績\\\"\");
  5. SET @b=CONCAT(\'SELECT IFNULL(cname,\\\'總成績\\\'),\',LEFT(@a,LENGTH(@a)-1),\' ,SUM(score) AS \\\"總成績\\\" FROM tb GROUP BY cname \');
  6.  
  7. /*班級成員總計部分**/
  8. SET @a2=\"\";
  9. SET @b2=CONCAT(\'SELECT \"all\",IFNULL(cname,\\\'總成績\\\'),\',LEFT(@a,LENGTH(@a)-1),\' ,SUM(score) AS \\\"總成績\\\" FROM tb GROUP BY cname \');
  10. SELECT @a2:=CONCAT(@a2,\'ROUND(AVG(`\',cource,\'`),2),\') FROM (SELECT DISTINCT cource FROM tb) A;
  11. SET @a2=CONCAT(@a2,\" ROUND(AVG(`平均成績`),2),ROUND(AVG(`總成績`),2) \");
  12. SET @c=CONCAT(\"SELECT \\\"班級平均數\\\",\",LEFT(@a2,LENGTH(@a)-1),\" FROM(\",@b2,\")tb2 GROUP BY tb2.all;\");
  13. SET @d=CONCAT(@b,\" UNION ALL \",@c);
  14.  
  15. PREPARE stmt1 FROM @d;
  16. EXECUTE stmt1;

檢視執行結果如下,已經達到效果:

  1. mysql> /*僅僅班級成員部分*/
  2. mysql> SET @a=\'\';
  3. QUERY OK, 0 ROWS affected (0.00 sec)
  4.  
  5. mysql> SELECT @a:=CONCAT(@a,\'SUM(IF(cource=\\\'\',cource,\'\\\'\',\',score,0)) AS \',cource,\',\') FROM (SELECT DISTINCT cource FROM tb) A;
  6. +-----------------------------------------------------------------------------------------------------------------------------------+
  7. | @a:=CONCAT(@a,\'SUM(IF(cource=\\\'\',cource,\'\\\'\',\',score,0)) AS \',cource,\',\') |
  8. +-----------------------------------------------------------------------------------------------------------------------------------+
  9. | SUM(IF(cource=\'語文\',score,0)) AS 語文, |
  10. | SUM(IF(cource=\'語文\',score,0)) AS 語文,SUM(IF(cource=\'數學\',score,0)) AS 數學, |
  11. | SUM(IF(cource=\'語文\',score,0)) AS 語文,SUM(IF(cource=\'數學\',score,0)) AS 數學,SUM(IF(cource=\'物理\',score,0)) AS 物理, |
  12. +-----------------------------------------------------------------------------------------------------------------------------------+
  13. 3 ROWS IN SET (0.00 sec)
  14.  
  15. mysql> SET @a=CONCAT(@a,\"ROUND(AVG(score) ,2) AS \\\"平均成績\\\"\");
  16. QUERY OK, 0 ROWS affected (0.00 sec)
  17.  
  18. mysql> SET @b=CONCAT(\'SELECT IFNULL(cname,\\\'總成績\\\'),\',LEFT(@a,LENGTH(@a)-1),\' ,SUM(score) AS \\\"總成績\\\" FROM tb GROUP BY cname \');
  19. QUERY OK, 0 ROWS affected (0.00 sec)
  20.  
  21. mysql>
  22. mysql> /*班級成員總計部分**/
  23. mysql> SET @a2=\"\";
  24. QUERY OK, 0 ROWS affected (0.00 sec)
  25.  
  26. mysql> SET @b2=CONCAT(\'SELECT \"all\",IFNULL(cname,\\\'總成績\\\'),\',LEFT(@a,LENGTH(@a)-1),\' ,SUM(score) AS \\\"總成績\\\" FROM tb GROUP BY cname \');
  27. QUERY OK, 0 ROWS affected (0.00 sec)
  28.  
  29. mysql> SELECT @a2:=CONCAT(@a2,\'ROUND(AVG(`\',cource,\'`),2),\') FROM (SELECT DISTINCT cource FROM tb) A;
  30. +-----------------------------------------------------------------------+
  31. | @a2:=CONCAT(@a2,\'ROUND(AVG(`\',cource,\'`),2),\') |
  32. +-----------------------------------------------------------------------+
  33. | ROUND(AVG(`語文`),2), |
  34. | ROUND(AVG(`語文`),2),ROUND(AVG(`數學`),2), |
  35. | ROUND(AVG(`語文`),2),ROUND(AVG(`數學`),2),ROUND(AVG(`物理`),2), |
  36. +-----------------------------------------------------------------------+
  37. 3 ROWS IN SET (0.00 sec)
  38.  
  39. mysql> SET @a2=CONCAT(@a2,\" ROUND(AVG(`平均成績`),2),ROUND(AVG(`總成績`),2) \");
  40. QUERY OK, 0 ROWS affected (0.00 sec)
  41.  
  42. mysql> SET @c=CONCAT(\"SELECT \\\"班級平均數\\\",\",LEFT(@a2,LENGTH(@a)-1),\" FROM(\",@b2,\")tb2 GROUP BY tb2.all;\");
  43. QUERY OK, 0 ROWS affected (0.00 sec)
  44.  
  45. mysql> SET @d=CONCAT(@b,\" UNION ALL \",@c);
  46. QUERY OK, 0 ROWS affected (0.00 sec)
  47.  
  48. mysql>
  49. mysql> PREPARE stmt1 FROM @d;
  50. QUERY OK, 0 ROWS affected (0.00 sec)
  51. Statement prepared
  52.  
  53. mysql> EXECUTE stmt1;
  54. +---------------------------+--------+--------+--------+--------------+-----------+
  55. | IFNULL(cname,\'總成績\') | 語文 | 數學 | 物理 | 平均成績 | 總成績 |
  56. +---------------------------+--------+--------+--------+--------------+-----------+
  57. | 張三 | 74.00 | 83.00 | 93.00 | 83.33 | 250.00 |
  58. | 李四 | 74.00 | 84.00 | 94.00 | 84.00 | 252.00 |
  59. | 班級平均數 | 74.00 | 83.50 | 93.50 | 83.67 | 251.00 |
  60. +---------------------------+--------+--------+--------+--------------+-----------+
  61. 3 ROWS IN SET (0.00 sec)
  62.  
  63. mysql>

 

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29734436/viewspace-1266896/,如需轉載,請註明出處,否則將追究法律責任。

相關文章