Mysql行轉換爲列

需要統計數據生成簡易報表,由原表格數據是單行的形式,最好轉換爲列表格式,由網上介紹方法實現如下:

希望獲得的最終效果見下:

+-------+------+-------+-------+--------+--------+--------+---------------------+---------+
| 房間  | 房租 | 水費  | 電費  | 衛生費 | 電視費 | 網絡費 | 記錄時間            | total   |
+-------+------+-------+-------+--------+--------+--------+---------------------+---------+
| 0201  400 |     0 |     0 |     10 |      0 |      0 | 2011-02-08 11:01:21 |     410 |
| 0204  150 |     0 |     0 |     10 |      0 |      0 | 2011-02-08 11:00:21 |     160 |
| 0206  150 |     0 |     0 |     10 |      0 |      0 | 2011-01-16 18:02:50 |     160 |
| 0302  350 | 40.92 | 18.91 |     20 |     50 |     50 | 2011-01-18 01:45:23 |  529.83 |
| 0306  150 |     0 |     0 |     10 |      0 |      0 | 2011-02-08 11:23:15 |     160 |
| 0308  200 |     0 |     0 |     10 |      0 |      0 | 2011-03-28 22:26:41 |     210 |
| total | 1400 | 40.92 | 18.91 |     70 |     50 |     50 | 2011-03-28 22:26:41 | 1629.83 |
+-------+------+-------+-------+--------+--------+--------+---------------------+---------+

實現的SQL語句見下:

mysql>  SELECT
    ->      IFNULL(RoomNo,'total') AS 房間,
    ->      SUM(IF(FeeName='房租',FeeMoney,0)) AS 房租,
    ->      SUM(IF(FeeName='水費',FeeMoney,0)) AS 水費,
    ->      SUM(IF(FeeName='電費',FeeMoney,0)) AS 電費,
    ->      SUM(IF(FeeName='衛生費',FeeMoney,0)) AS 衛生費,
    ->      SUM(IF(FeeName='電視費',FeeMoney,0)) AS 電視費,
    ->      SUM(IF(FeeName='網絡費',FeeMoney,0)) AS 網絡費,
    ->      IFNULL(CDate, CDate) AS 記錄時間,
    ->      SUM(IF(FeeName='total',FeeMoney,0)) AS total
    ->  FROM (
    -> select no.RoomNo as RoomNo, IFNULL(f.FeeName, 'total') as FeeName, SUM(f.FeeMoney) as FeeMoney, f.CreateDate as CDate
    -> from roomnoinfo no, Fee f
    -> where no.bid=1 and no.beempty='full' and no.RoomNo=f.RoomNo and
    -> f.CreateDate < '2011-03-31' and f.CreateDate >'2011-01-01'
    -> GROUP BY RoomNO, FeeName
    -> WITH ROLLUP
    -> HAVING RoomNO IS NOT NULL
    ->  ) AS A
    ->  GROUP BY RoomNo
    ->  WITH ROLLUP;

源數據的表格式如下:

mysql> select RoomNo, CreateDate, FeeName, FeeMoney from Fee where bid=1;
+--------+---------------------+---------+----------+
| RoomNo | CreateDate          | FeeName | FeeMoney |
+--------+---------------------+---------+----------+
| 0101   | 2011-01-15 22:41:24 | 房租        200 |
| 0101   | 2011-01-15 22:41:24 | 水費       13.2 |
| 0101   | 2011-01-15 22:41:24 | 電費        6.1 |
| 0102   | 2011-01-16 17:01:52 | 房租        150 |
| 0102   | 2011-01-16 17:01:52 | 水費      145.2 |
| 0102   | 2011-01-16 17:01:52 | 電費       67.1 |
| 0102   | 2011-01-16 17:01:52 | 衛生費       10 |
| 0204   | 2011-02-08 11:00:21 | 房租        150 |
| 0204   | 2011-02-08 11:00:21 | 水費       NULL |
| 0204   | 2011-02-08 11:00:21 | 電費       NULL |
| 0204   | 2011-02-08 11:00:21 | 衛生費       10 |
| 0206   | 2011-01-16 18:02:50 | 房租        150 |
| 0206   | 2011-01-16 18:02:50 | 水費       NULL |
| 0206   | 2011-01-16 18:02:50 | 電費       NULL |
| 0206   | 2011-01-16 18:02:50 | 衛生費       10 |
| 0302   | 2011-01-18 01:42:35 | 房租        150 |
| 0302   | 2011-01-18 01:42:35 | 水費      40.92 |
| 0302   | 2011-01-18 01:42:35 | 電費      18.91 |
| 0302   | 2011-01-18 01:42:35 | 衛生費       10 |
| 0302   | 2011-01-18 01:45:23 | 衛生費       10 |
| 0302   | 2011-01-18 01:45:23 | 房租        200 |
| 0302   | 2011-01-18 01:45:23 | 網絡費       50 |
| 0302   | 2011-01-18 01:45:23 | 電視費       50 |
| 0306   | 2011-02-08 11:23:15 | 房租        150 |
| 0306   | 2011-02-08 11:23:15 | 水費       NULL |
| 0306   | 2011-02-08 11:23:15 | 電費       NULL |
| 0306   | 2011-02-08 11:23:15 | 衛生費       10 |
| 0308   | 2011-03-28 22:26:41 | 房租        200 |
| 0308   | 2011-03-28 22:26:41 | 水費       NULL |
| 0308   | 2011-03-28 22:26:41 | 電費       NULL |
| 0308   | 2011-03-28 22:26:41 | 衛生費       10 |
+--------+---------------------+---------+----------+
31 rows in set (0.02 sec)

 

原文介紹地址 http://blogold.chinaunix.net/u3/90603/showart_2017912.html

 

數據樣本:

create table tx(
 id int primary key,
 c1 char(2),
 c2 char(2),
 c3 int
);

insert into tx values
(1 ,'A1','B1',9),
(2 ,'A2','B1',7),
(3 ,'A3','B1',4),
(4 ,'A4','B1',2),
(5 ,'A1','B2',2),
(6 ,'A2','B2',9),
(7 ,'A3','B2',8),
(8 ,'A4','B2',5),
(9 ,'A1','B3',1),
(10 ,'A2','B3',8),
(11 ,'A3','B3',8),
(12 ,'A4','B3',6),
(13 ,'A1','B4',8),
(14 ,'A2','B4',2),
(15 ,'A3','B4',6),
(16 ,'A4','B4',9),
(17 ,'A1','B4',3),
(18 ,'A2','B4',5),
(19 ,'A3','B4',2),
(20 ,'A4','B4',5);

 

mysql> select * from tx;
+----+------+------+------+
| id | c1   | c2   | c3   |
+----+------+------+------+
1 | A1   | B1     9 |
2 | A2   | B1     7 |
3 | A3   | B1     4 |
4 | A4   | B1     2 |
5 | A1   | B2     2 |
6 | A2   | B2     9 |
7 | A3   | B2     8 |
8 | A4   | B2     5 |
9 | A1   | B3     1 |
| 10 | A2   | B3     8 |
| 11 | A3   | B3     8 |
| 12 | A4   | B3     6 |
| 13 | A1   | B4     8 |
| 14 | A2   | B4     2 |
| 15 | A3   | B4     6 |
| 16 | A4   | B4     9 |
| 17 | A1   | B4     3 |
| 18 | A2   | B4     5 |
| 19 | A3   | B4     2 |
| 20 | A4   | B4     5 |
+----+------+------+------+
20 rows in set (0.00 sec)

mysql>

期望結果

+------+-----+-----+-----+-----+------+
|C1    |B1   |B2   |B3   |B4   |Total |
+------+-----+-----+-----+-----+------+
|A1    |9    |2    |1    |11   |23    |
|A2    |7    |9    |8    |7    |31    |
|A3    |4    |8    |8    |8    |28    |
|A4    |2    |5    |6    |14   |27    |
|Total |22   |24   |23   |40   |109   |
+------+-----+-----+-----+-----+------+

1. 利用SUM(IF()) 生成列 + WITH ROLLUP 生成彙總行,並利用 IFNULL將彙總行標題顯示爲 Total

mysql> SELECT
    ->     IFNULL(c1,'total') AS total,
    ->     SUM(IF(c2='B1',c3,0)) AS B1,
    ->     SUM(IF(c2='B2',c3,0)) AS B2,
    ->     SUM(IF(c2='B3',c3,0)) AS B3,
    ->     SUM(IF(c2='B4',c3,0)) AS B4,
    ->     SUM(IF(c2='total',c3,0)) AS total
    -> FROM (
    ->     SELECT c1,IFNULL(c2,'total') AS c2,SUM(c3) AS c3
    ->     FROM tx
    ->     GROUP BY c1,c2
    ->     WITH ROLLUP
    ->     HAVING c1 IS NOT NULL
    -> ) AS A
    -> GROUP BY c1
    -> WITH ROLLUP;
+-------+------+------+------+------+-------+
| total | B1   | B2   | B3   | B4   | total |
+-------+------+------+------+------+-------+
| A1      9 |    2 |    1 |   11 |    23 |
| A2      7 |    9 |    8 |    7 |    31 |
| A3      4 |    8 |    8 |    8 |    28 |
| A4      2 |    5 |    6 |   14 |    27 |
| total |   22 |   24 |   23 |   40 |   109 |
+-------+------+------+------+------+-------+
5 rows in set, 1 warning (0.00 sec)

2. 利用SUM(IF()) 生成列 + UNION 生成彙總行,並利用 IFNULL將彙總行標題顯示爲 Total
mysql> select c1,
    -> sum(if(c2='B1',C3,0)) AS B1,
    -> sum(if(c2='B2',C3,0)) AS B2,
    -> sum(if(c2='B3',C3,0)) AS B3,
    -> sum(if(c2='B4',C3,0)) AS B4,SUM(C3) AS TOTAL
    -> from tx
    -> group by C1
    -> UNION
    -> SELECT 'TOTAL',sum(if(c2='B1',C3,0)) AS B1,
    -> sum(if(c2='B2',C3,0)) AS B2,
    -> sum(if(c2='B3',C3,0)) AS B3,
    -> sum(if(c2='B4',C3,0)) AS B4,SUM(C3) FROM TX
    -> ;
+-------+------+------+------+------+-------+
| c1    | B1   | B2   | B3   | B4   | TOTAL |
+-------+------+------+------+------+-------+
| A1      9 |    2 |    1 |   11 |    23 |
| A2      7 |    9 |    8 |    7 |    31 |
| A3      4 |    8 |    8 |    8 |    28 |
| A4      2 |    5 |    6 |   14 |    27 |
| TOTAL |   22 |   24 |   23 |   40 |   109 |
+-------+------+------+------+------+-------+
5 rows in set (0.00 sec)

mysql>

 

3.  利用SUM(IF()) 生成列,直接生成結果不再利用子查詢
mysql> select ifnull(c1,'total'),
    -> sum(if(c2='B1',C3,0)) AS B1,
    -> sum(if(c2='B2',C3,0)) AS B2,
    -> sum(if(c2='B3',C3,0)) AS B3,
    -> sum(if(c2='B4',C3,0)) AS B4,SUM(C3) AS TOTAL
    -> from tx
    -> group by C1 with rollup ;
+--------------------+------+------+------+------+-------+
| ifnull(c1,'total') | B1   | B2   | B3   | B4   | TOTAL |
+--------------------+------+------+------+------+-------+
| A1                   9 |    2 |    1 |   11 |    23 |
| A2                   7 |    9 |    8 |    7 |    31 |
| A3                   4 |    8 |    8 |    8 |    28 |
| A4                   2 |    5 |    6 |   14 |    27 |
| total               22 |   24 |   23 |   40 |   109 |
+--------------------+------+------+------+------+-------+
5 rows in set (0.00 sec)

mysql>


4. 動態,適用於列不確定情況,

mysql> SET @EE='';
mysql> SELECT @EE:=CONCAT(@EE,'SUM(IF(C2=\'',C2,'\'',',C3,0)) AS ',C2,',') FROM (SELECT DISTINCT C2 FROM TX) A;

 

mysql> SET @QQ=CONCAT('SELECT ifnull(c1,\'total\'),',LEFT(@EE,LENGTH(@EE)-1),' ,SUM(C3) AS TOTAL FROM TX GROUP BY C1 WITH ROLLUP');
Query OK, 0 rows affected (0.00 sec)

mysql> PREPARE stmt2 FROM @QQ;
Query OK, 0 rows affected (0.00 sec)
Statement prepared

mysql> EXECUTE stmt2;
+--------------------+------+------+------+------+-------+
| ifnull(c1,'total') | B1   | B2   | B3   | B4   | TOTAL |
+--------------------+------+------+------+------+-------+
| A1                   9 |    2 |    1 |   11 |    23 |
| A2                   7 |    9 |    8 |    7 |    31 |
| A3                   4 |    8 |    8 |    8 |    28 |
| A4                   2 |    5 |    6 |   14 |    27 |
| total               22 |   24 |   23 |   40 |   109 |
+--------------------+------+------+------+------+-------+
5 rows in set (0.00 sec)

mysql>

以上均由網友  liangCK , wwwwb , WWWWA , dap570 提供, 再次感謝他們的支持。

其實數據庫中也可以用 CASE WHEN / DECODE 代替 IF

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章