MySQL数据行怎么转为列

Posted 知其黑、受其白

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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)

这里行转列是将原来的 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、使用 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;

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;

注意点:

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。

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;
+--------+--------+--------+--------+--------+-------+
| 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)

IFNULL() 函数

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

实例

第一个参数为 NULL:
SELECT IFNULL(NULL, "RUNOOB");
以上实例输出结果为:RUNOOB

第一个参数不为 NULL:
SELECT IFNULL("Hello", "RUNOOB");
以上实例输出结果为:Hello

WITH ROLLUP

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

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

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;
+--------+--------+--------+--------+--------+-------+
| 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)

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;
+--------+--------+--------+--------+--------+-------+
| 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)

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

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

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)

建表语句

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;

插入数据

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);

以上是关于MySQL数据行怎么转为列的主要内容,如果未能解决你的问题,请参考以下文章

MySQL - 如何将列转为行?

MySQL - 如何将列转为行?

MySQL - 如何将列转为行?

MySQL - 如何将列转为行?

MySQL 动态地将行转为列

oracle行转列sql怎么写?