sql查询:行转列和 列转行
一、行转列将原本同一列下多行的不同内容作为多个字段,输出对应内容。表及数据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 '科目',
目录
3、使用SUM(IF()) 生成列 + WITH ROLLUP 生成汇总行
4、使用SUM(IF()) 生成列,直接生成汇总结果,不再利用子查询
5、使用SUM(IF()) 生成列 + UNION 生成汇总行,并利用 IFNULL将汇总行标题显示为 Total
一、行转列
将原本同一列下多行的不同内容作为多个字段,输出对应内容。
表及数据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 :不会对结果进行去重处理,只是简单地将两个结果集合并。
参考文章:
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)