zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    2019-9-2-C#命令行解析工具
    2018-9-20-断点调试-Windows-源代码
    2018-9-20-断点调试-Windows-源代码
    2018-8-10-dot-net-core-使用-IPC-进程通信
    2018-8-10-dot-net-core-使用-IPC-进程通信
    Java实现 LeetCode 592 分数加减运算(纯体力活)
    Java实现 LeetCode 590 N叉树的后序遍历(遍历树,迭代法)
    Java实现 LeetCode 590 N叉树的后序遍历(遍历树,迭代法)
    Java实现 LeetCode 590 N叉树的后序遍历(遍历树,迭代法)
    Java实现 LeetCode 589 N叉树的前序遍历(遍历树)
  • 原文地址:https://www.cnblogs.com/lhj588/p/2550392.html
Copyright © 2011-2022 走看看