• MySQL数据行怎么转为列


    行转列

    即将原本同一列下多行的不同内容作为多个字段,输出对应内容。

    查询数据表中的内容(即转换前的结果)

    mysql> select * from tb_score;
    +----+--------+---------+-------+
    | id | userid | subject | score |
    +----+--------+---------+-------+
    |  1 | 001    | 语文    |    90 |
    |  2 | 001    | 数学    |    92 |
    |  3 | 001    | 英语    |    80 |
    |  4 | 002    | 语文    |    88 |
    |  5 | 002    | 数学    |    90 |
    |  6 | 002    | 英语    |  75.5 |
    |  7 | 003    | 语文    |    70 |
    |  8 | 003    | 数学    |    85 |
    |  9 | 003    | 英语    |    90 |
    | 10 | 003    | 政治    |    82 |
    +----+--------+---------+-------+
    10 rows in set (0.00 sec)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    这里行转列是将原来的 subject 字段的多行内容选出来,作为结果集中的不同列,并根据userid 进行分组显示对应的 score

    +--------+--------+--------+--------+--------+
    | userid | 语文   | 数学   | 英语   | 政治   |
    +--------+--------+--------+--------+--------+
    | 001    |     90 |     92 |     80 |      0 |
    | 002    |     88 |     90 |   75.5 |      0 |
    | 003    |     70 |     85 |     90 |     82 |
    +--------+--------+--------+--------+--------+
    3 rows in set (0.00 sec)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    1、使用 case…when…then 进行行转列

    SELECT userid,
    SUM(CASE `subject` WHEN '语文' THEN score ELSE 0 END) as '语文',
    SUM(CASE `subject` WHEN '数学' THEN score ELSE 0 END) as '数学',
    SUM(CASE `subject` WHEN '英语' THEN score ELSE 0 END) as '英语',
    SUM(CASE `subject` WHEN '政治' THEN score ELSE 0 END) as '政治' 
    FROM tb_score 
    GROUP BY userid;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2、使用 IF() 进行行转列

    SELECT userid,
    SUM(IF(`subject`='语文',score,0)) as '语文',
    SUM(IF(`subject`='数学',score,0)) as '数学',
    SUM(IF(`subject`='英语',score,0)) as '英语',
    SUM(IF(`subject`='政治',score,0)) as '政治' 
    FROM tb_score 
    GROUP BY userid;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    注意点:

    SUM() 是为了能够使用 GROUP BY 根据 userid 进行分组,因为每一个 userid 对应的subject="语文" 的记录只有一条,所以 SUM() 的值就等于对应那一条记录的 score 的值。

    假如 userid ='001' and subject='语文' 的记录有两条,则此时 SUM() 的值将会是这两条记录的和,同理,使用 Max() 的值将会是这两条记录里面值最大的一个。

    但是正常情况下,一个 user 对应一个 subject 只有一个分数,因此可以使用 SUM()MAX()、MIN()、AVG() 等聚合函数都可以达到行转列的效果。

    IF(`subject`='语文',score,0) 作为条件,
    即对所有 subject='语文' 的记录的 score 字段进行 SUM()、MAX()、MIN()、AVG()操作,
    如果 score 没有值则默认为0。
    
    • 1
    • 2
    • 3

    3、利用 SUM(IF()) 生成列 + WITH ROLLUP 生成汇总行,并利用 IFNULL 将汇总行标题显示为 Total

    SELECT IFNULL(userid,'total') AS userid,
    SUM(IF(`subject`='语文',score,0)) AS 语文,
    SUM(IF(`subject`='数学',score,0)) AS 数学,
    SUM(IF(`subject`='英语',score,0)) AS 英语,
    SUM(IF(`subject`='政治',score,0)) AS 政治,
    SUM(IF(`subject`='total',score,0)) AS total
    FROM(
        SELECT userid,IFNULL(`subject`,'total') AS `subject`,SUM(score) AS score
        FROM tb_score
        GROUP BY userid,`subject`
        WITH ROLLUP
        HAVING userid IS NOT NULL
    )AS A 
    GROUP BY userid
    WITH ROLLUP;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    +--------+--------+--------+--------+--------+-------+
    | userid | 语文   | 数学   | 英语   | 政治   | total |
    +--------+--------+--------+--------+--------+-------+
    | 001    |     90 |     92 |     80 |      0 |   262 |
    | 002    |     88 |     90 |   75.5 |      0 | 253.5 |
    | 003    |     70 |     85 |     90 |     82 |   327 |
    | total  |    248 |    267 |  245.5 |     82 | 842.5 |
    +--------+--------+--------+--------+--------+-------+
    4 rows in set, 2 warnings (0.00 sec)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    IFNULL() 函数

    IFNULL() 函数用于判断第一个表达式是否为 NULL,如果为 NULL 则返回第二个参数的值,如果不为 NULL 则返回第一个参数的值。

    实例
    
    第一个参数为 NULL:
    SELECT IFNULL(NULL, "RUNOOB");
    以上实例输出结果为:RUNOOB
    
    第一个参数不为 NULL:
    SELECT IFNULL("Hello", "RUNOOB");
    以上实例输出结果为:Hello
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    WITH ROLLUP

    当需要对数据库数据进行分类统计的时候,往往会用上 groupby 进行分组。
    而在 groupby 后面还可以加入 withcubewithrollup 等关键字对数据进行汇总。

    SELECT
    	IFNULL(SUBJECT, "统计") as total,
    	SUM(score) AS score
    FROM
    	tb_score
    GROUP BY
    	SUBJECT WITH ROLLUP;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    +--------+-------+
    | total  | score |
    +--------+-------+
    | 政治   |    82 |
    | 数学   |   267 |
    | 英语   | 245.5 |
    | 语文   |   248 |
    | 统计   | 842.5 |
    +--------+-------+
    5 rows in set (0.00 sec)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    4、利用 SUM(IF()) 生成列 + UNION 生成汇总行,并利用 IFNULL将汇总行标题显示为 Total

    SELECT userid,
    SUM(IF(`subject`='语文',score,0)) AS 语文,
    SUM(IF(`subject`='数学',score,0)) AS 数学,
    SUM(IF(`subject`='英语',score,0)) AS 英语,
    SUM(IF(`subject`='政治',score,0)) AS 政治,
    SUM(score) AS TOTAL 
    FROM tb_score
    GROUP BY userid
    UNION
    SELECT 'TOTAL',SUM(IF(`subject`='语文',score,0)) AS 语文,
    SUM(IF(`subject`='数学',score,0)) AS 数学,
    SUM(IF(`subject`='英语',score,0)) AS 英语,
    SUM(IF(`subject`='政治',score,0)) AS 政治,
    SUM(score) FROM tb_score;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    +--------+--------+--------+--------+--------+-------+
    | userid | 语文   | 数学   | 英语   | 政治   | TOTAL |
    +--------+--------+--------+--------+--------+-------+
    | 001    |     90 |     92 |     80 |      0 |   262 |
    | 002    |     88 |     90 |   75.5 |      0 | 253.5 |
    | 003    |     70 |     85 |     90 |     82 |   327 |
    | TOTAL  |    248 |    267 |  245.5 |     82 | 842.5 |
    +--------+--------+--------+--------+--------+-------+
    4 rows in set (0.00 sec)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    5、利用 SUM(IF()) 生成列,直接生成结果不再利用子查询

    SELECT IFNULL(userid,'TOTAL') AS userid,
    SUM(IF(`subject`='语文',score,0)) AS 语文,
    SUM(IF(`subject`='数学',score,0)) AS 数学,
    SUM(IF(`subject`='英语',score,0)) AS 英语,
    SUM(IF(`subject`='政治',score,0)) AS 政治,
    SUM(score) AS TOTAL 
    FROM tb_score
    GROUP BY userid WITH ROLLUP;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    +--------+--------+--------+--------+--------+-------+
    | userid | 语文   | 数学   | 英语   | 政治   | TOTAL |
    +--------+--------+--------+--------+--------+-------+
    | 001    |     90 |     92 |     80 |      0 |   262 |
    | 002    |     88 |     90 |   75.5 |      0 | 253.5 |
    | 003    |     70 |     85 |     90 |     82 |   327 |
    | TOTAL  |    248 |    267 |  245.5 |     82 | 842.5 |
    +--------+--------+--------+--------+--------+-------+
    4 rows in set, 1 warning (0.00 sec)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    6、合并字段显示:利用group_concat()

    SELECT
    	userid,
    	GROUP_CONCAT(`subject`, ":", score) AS 成绩
    FROM
    	tb_score
    GROUP BY
    	userid;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    +--------+-----------------------------------------+
    | userid | 成绩                                    |
    +--------+-----------------------------------------+
    | 001    | 语文:90,数学:92,英语:80                 |
    | 002    | 英语:75.5,数学:90,语文:88               |
    | 003    | 语文:70,数学:85,英语:90,政治:82         |
    +--------+-----------------------------------------+
    3 rows in set (0.00 sec)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    group_concat(),手册上说明:该函数返回带有来自一个组的连接的非 NULL 值的字符串结果。

    比较抽象,难以理解。通俗点理解,其实是这样的:group_concat()会计算哪些行属于同一组,将属于同一组的列显示出来。要返回哪些列,由函数参数(就是字段名)决定。分组必须有个标准,就是根据group by指定的列进行分组。

    结论:group_concat()函数可以很好的建属于同一分组的多个行转化为一个列。

    环境

    本教程操作环境:windows10系统

    C:\Users\Administrator>mysql --version
    mysql  Ver 14.14 Distrib 5.6.29, for Win64 (x86_64)
    
    • 1
    • 2

    建表语句

    DROP TABLE IF EXISTS tb_score;
    CREATE TABLE tb_score(
        id INT(11) NOT NULL auto_increment,
        userid VARCHAR(20) NOT NULL COMMENT '用户id',
        subject VARCHAR(20) COMMENT '科目',
        score DOUBLE COMMENT '成绩',
        PRIMARY KEY(id)
    )ENGINE = INNODB DEFAULT CHARSET = utf8;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    插入数据

    INSERT INTO tb_score(userid,subject,score) VALUES ('001','语文',90);
    INSERT INTO tb_score(userid,subject,score) VALUES ('001','数学',92);
    INSERT INTO tb_score(userid,subject,score) VALUES ('001','英语',80);
    INSERT INTO tb_score(userid,subject,score) VALUES ('002','语文',88);
    INSERT INTO tb_score(userid,subject,score) VALUES ('002','数学',90);
    INSERT INTO tb_score(userid,subject,score) VALUES ('002','英语',75.5);
    INSERT INTO tb_score(userid,subject,score) VALUES ('003','语文',70);
    INSERT INTO tb_score(userid,subject,score) VALUES ('003','数学',85);
    INSERT INTO tb_score(userid,subject,score) VALUES ('003','英语',90);
    INSERT INTO tb_score(userid,subject,score) VALUES ('003','政治',82);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
  • 相关阅读:
    HTML+CSS+JS静态网页设计【二十四节气】期末课程大作业
    人工智能机器学习-飞桨神经网络与深度学习
    cka练习
    微信小程序数据传递的方式-页面数据的存取
    sum = sum * 10 + ch - ‘0‘;的含义
    Linux性能基础:CPU、内存、磁盘等概述
    Linux 打开的文件过多 too many open files
    mosquitto2.0.14 windowsx64配置说明
    SpringBoot整合RabbitMQ实现消息延迟队列
    dirsearch网站目录暴力破解
  • 原文地址:https://blog.csdn.net/weiguang102/article/details/127634238