目录

 

一、行转列

1、使用case…when…then 

 2、使用SUM(IF()) 生成列 

3、使用SUM(IF()) 生成列 + WITH ROLLUP 生成汇总行 

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

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

6、动态查询列值不确定的情况

7、合并字段显示:group_concat()

二、列转行


一、行转列

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

表及数据sql:

CREATE TABLE `tb_score` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `userid` varchar(20) NOT NULL COMMENT '用户id',
  `subjectName` varchar(20) DEFAULT NULL COMMENT '科目',
  `score` double DEFAULT NULL COMMENT '成绩',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8;

INSERT INTO `tb_score`(`id`, `userid`, `subjectName`, `score`) VALUES (1, '001', '语文', 90);
INSERT INTO `tb_score`(`id`, `userid`, `subjectName`, `score`) VALUES (2, '001', '数学', 92);
INSERT INTO `tb_score`(`id`, `userid`, `subjectName`, `score`) VALUES (3, '001', '英语', 80);
INSERT INTO `tb_score`(`id`, `userid`, `subjectName`, `score`) VALUES (4, '002', '语文', 88);
INSERT INTO `tb_score`(`id`, `userid`, `subjectName`, `score`) VALUES (5, '002', '数学', 90);
INSERT INTO `tb_score`(`id`, `userid`, `subjectName`, `score`) VALUES (6, '002', '英语', 75.5);
INSERT INTO `tb_score`(`id`, `userid`, `subjectName`, `score`) VALUES (7, '003', '语文', 70);
INSERT INTO `tb_score`(`id`, `userid`, `subjectName`, `score`) VALUES (8, '003', '数学', 85);
INSERT INTO `tb_score`(`id`, `userid`, `subjectName`, `score`) VALUES (9, '003', '英语', 90);
INSERT INTO `tb_score`(`id`, `userid`, `subjectName`, `score`) VALUES (10, '003', '政治', 82);
INSERT INTO `tb_score`(`id`, `userid`, `subjectName`, `score`) VALUES (11, '004', '政治', 82);
INSERT INTO `tb_score`(`id`, `userid`, `subjectName`, `score`) VALUES (12, '004', '英语', 83);

行数据:

列数据:

1、使用case…when…then 

SELECT
	userid,
	SUM( CASE subjectName WHEN '语文' THEN score ELSE 0 END ) '语文',
	SUM( CASE subjectName WHEN '数学' THEN score ELSE 0 END ) '数学',
	SUM( CASE subjectName WHEN '英语' THEN score ELSE 0 END ) '英语',
	SUM( CASE subjectName WHEN '政治' THEN score ELSE 0 END ) '政治' 
FROM
	tb_score 
GROUP BY
	userid;

 2、使用SUM(IF()) 生成列 

SELECT
	userid,
	SUM( IF ( subjectName = '语文', score, 0 ) ) '语文',
	SUM( IF ( subjectName = '数学', score, 0 ) ) '数学',
	SUM( IF ( subjectName = '英语', score, 0 ) ) '英语',
	SUM( IF ( subjectName = '政治', score, 0 ) ) '政治' 
FROM
	tb_score 
GROUP BY
	userid;

3、使用SUM(IF()) 生成列 + WITH ROLLUP 生成汇总行 

MySQL提供了 group by with rollup 函数进行group by 字段的汇总,但是与order by 互斥的不能同时用。

SELECT
	IFNULL( userid, 'total' ) AS userid,
	SUM( IF ( subjectName = '语文', score, 0 ) ) '语文',
	SUM( IF ( subjectName = '数学', score, 0 ) ) '数学',
	SUM( IF ( subjectName = '英语', score, 0 ) ) '英语',
	SUM( IF ( subjectName = '政治', score, 0 ) ) '政治',
	SUM( IF ( subjectName = 'total', score, 0 ) ) AS 'total' 
FROM
	(
		SELECT
			userid,
			IFNULL( subjectName, 'total' ) AS subjectName,
			SUM( score ) AS score 
		FROM
			tb_score 
		GROUP BY userid, subjectName WITH ROLLUP 
	) AS a
GROUP BY userid
WITH ROLLUP;

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

SELECT IFNULL(userid,'total') AS userid,
SUM(IF(subjectName='语文',score,0)) AS '语文',
SUM(IF(subjectName='数学',score,0)) AS '数学',
SUM(IF(subjectName='英语',score,0)) AS '英语',
SUM(IF(subjectName='政治',score,0)) AS '政治',
SUM(score) AS total
FROM tb_score
GROUP BY userid WITH ROLLUP;

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

SELECT userid,
SUM(IF(subjectName='语文',score,0)) AS '语文',
SUM(IF(subjectName='数学',score,0)) AS '数学',
SUM(IF(subjectName='英语',score,0)) AS '英语',
SUM(IF(subjectName='政治',score,0)) AS '政治',
SUM(score) AS total
FROM tb_score
GROUP BY userid
UNION
SELECT 'total',SUM(IF(subjectName='语文',score,0)) AS '语文',
SUM(IF(subjectName='数学',score,0)) AS '数学',
SUM(IF(subjectName='英语',score,0)) AS '英语',
SUM(IF(subjectName='政治',score,0)) AS '政治',
SUM(score) FROM tb_score;

6、动态查询列值不确定的情况

SET @EE='';
select @EE :=CONCAT(@EE,'sum(if(subject= \'',subject,'\',score,0)) as ',subject, ',') AS aa FROM (SELECT DISTINCT subject FROM tb_score) A ;

SET @QQ = CONCAT('select ifnull(userid,\'total\')as userid,',@EE,' sum(score) as total from tb_score group by userid WITH ROLLUP');
-- SELECT @QQ;

PREPARE stmt FROM @QQ;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

3、4、5、6、执行结果如下:

7、合并字段显示:group_concat()

SELECT userid,GROUP_CONCAT(`subjectName`,":",score)AS 成绩 FROM tb_score GROUP BY userid;

group_concat() 计算哪些行属于同一组,将属于同一组的列显示出来。要返回哪些列,由函数参数(就是字段名)决定。分组 是根据group by指定的列进行分组。

执行结果:

二、列转行

CREATE TABLE tb_score1(
    id INT(11) NOT NULL auto_increment,
    userid VARCHAR(20) NOT NULL COMMENT '用户id',
    chinese_score DOUBLE COMMENT '语文成绩',
    math_score DOUBLE COMMENT '数学成绩',
    english_score DOUBLE COMMENT '英语成绩',
    politics_score DOUBLE COMMENT '政治成绩',
    PRIMARY KEY(id)
)ENGINE = INNODB DEFAULT CHARSET = utf8;

INSERT INTO tb_score1(userid,chinese_score,math_score,english_score,politics_score) VALUES ('001',90,92,80,0);
INSERT INTO tb_score1(userid,chinese_score,math_score,english_score,politics_score) VALUES ('002',88,90,75.5,0);
INSERT INTO tb_score1(userid,chinese_score,math_score,english_score,politics_score) VALUES ('003',70,85,90,82);
INSERT INTO tb_score1(userid,chinese_score,math_score,english_score,politics_score) VALUES ('003',0,0,83,82);

SELECT * FROM tb_score1;

查询结果:

列转行:将每个userid对应的多个科目的成绩查出来,通过UNION ALL将结果集加起来。

select userId,'语文' as subjectName,chinese_score as score from tb_score1
union all
select userId,'数学' as subjectName,math_score as score from tb_score1
union all
select userId,'英语' as subjectName,english_score as score from tb_score1
union all
select userId,'政治' as subjectName,politics_score as score from tb_score1;

转换后结果:

UNION : 会去掉重复记录,会排序,因为UNION 会做去重和排序处理,效率比UNION ALL慢很多。

UNION ALL :不会对结果进行去重处理,只是简单地将两个结果集合并。

 

参考文章:

一篇文章搞定mysql的 行转列(7种方法) 和 列转行

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐