sql查询:行转列和 列转行

目录

一、行转列

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:

  1. CREATE TABLE `tb_score` (
  2. `id` int(11) NOT NULL AUTO_INCREMENT,
  3. `userid` varchar(20) NOT NULL COMMENT '用户id',
  4. `subjectName` varchar(20) DEFAULT NULL COMMENT '科目',
  5. `score` double DEFAULT NULL COMMENT '成绩',
  6. PRIMARY KEY (`id`)
  7. ) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8;
  8. INSERT INTO `tb_score`(`id`, `userid`, `subjectName`, `score`) VALUES (1, '001', '语文', 90);
  9. INSERT INTO `tb_score`(`id`, `userid`, `subjectName`, `score`) VALUES (2, '001', '数学', 92);
  10. INSERT INTO `tb_score`(`id`, `userid`, `subjectName`, `score`) VALUES (3, '001', '英语', 80);
  11. INSERT INTO `tb_score`(`id`, `userid`, `subjectName`, `score`) VALUES (4, '002', '语文', 88);
  12. INSERT INTO `tb_score`(`id`, `userid`, `subjectName`, `score`) VALUES (5, '002', '数学', 90);
  13. INSERT INTO `tb_score`(`id`, `userid`, `subjectName`, `score`) VALUES (6, '002', '英语', 75.5);
  14. INSERT INTO `tb_score`(`id`, `userid`, `subjectName`, `score`) VALUES (7, '003', '语文', 70);
  15. INSERT INTO `tb_score`(`id`, `userid`, `subjectName`, `score`) VALUES (8, '003', '数学', 85);
  16. INSERT INTO `tb_score`(`id`, `userid`, `subjectName`, `score`) VALUES (9, '003', '英语', 90);
  17. INSERT INTO `tb_score`(`id`, `userid`, `subjectName`, `score`) VALUES (10, '003', '政治', 82);
  18. INSERT INTO `tb_score`(`id`, `userid`, `subjectName`, `score`) VALUES (11, '004', '政治', 82);
  19. INSERT INTO `tb_score`(`id`, `userid`, `subjectName`, `score`) VALUES (12, '004', '英语', 83);

行数据:

列数据:

1、使用case…when…then

  1. SELECT
  2. userid,
  3. SUM( CASE subjectName WHEN '语文' THEN score ELSE 0 END ) '语文',
  4. SUM( CASE subjectName WHEN '数学' THEN score ELSE 0 END ) '数学',
  5. SUM( CASE subjectName WHEN '英语' THEN score ELSE 0 END ) '英语',
  6. SUM( CASE subjectName WHEN '政治' THEN score ELSE 0 END ) '政治'
  7. FROM
  8. tb_score
  9. GROUP BY
  10. userid;

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

  1. SELECT
  2. userid,
  3. SUM( IF ( subjectName = '语文', score, 0 ) ) '语文',
  4. SUM( IF ( subjectName = '数学', score, 0 ) ) '数学',
  5. SUM( IF ( subjectName = '英语', score, 0 ) ) '英语',
  6. SUM( IF ( subjectName = '政治', score, 0 ) ) '政治'
  7. FROM
  8. tb_score
  9. GROUP BY
  10. userid;

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

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

  1. SELECT
  2. IFNULL( userid, 'total' ) AS userid,
  3. SUM( IF ( subjectName = '语文', score, 0 ) ) '语文',
  4. SUM( IF ( subjectName = '数学', score, 0 ) ) '数学',
  5. SUM( IF ( subjectName = '英语', score, 0 ) ) '英语',
  6. SUM( IF ( subjectName = '政治', score, 0 ) ) '政治',
  7. SUM( IF ( subjectName = 'total', score, 0 ) ) AS 'total'
  8. FROM
  9. (
  10. SELECT
  11. userid,
  12. IFNULL( subjectName, 'total' ) AS subjectName,
  13. SUM( score ) AS score
  14. FROM
  15. tb_score
  16. GROUP BY userid, subjectName WITH ROLLUP
  17. ) AS a
  18. GROUP BY userid
  19. WITH ROLLUP;

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

  1. SELECT IFNULL(userid,'total') AS userid,
  2. SUM(IF(subjectName='语文',score,0)) AS '语文',
  3. SUM(IF(subjectName='数学',score,0)) AS '数学',
  4. SUM(IF(subjectName='英语',score,0)) AS '英语',
  5. SUM(IF(subjectName='政治',score,0)) AS '政治',
  6. SUM(score) AS total
  7. FROM tb_score
  8. GROUP BY userid WITH ROLLUP;

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

  1. SELECT userid,
  2. SUM(IF(subjectName='语文',score,0)) AS '语文',
  3. SUM(IF(subjectName='数学',score,0)) AS '数学',
  4. SUM(IF(subjectName='英语',score,0)) AS '英语',
  5. SUM(IF(subjectName='政治',score,0)) AS '政治',
  6. SUM(score) AS total
  7. FROM tb_score
  8. GROUP BY userid
  9. UNION
  10. SELECT 'total',SUM(IF(subjectName='语文',score,0)) AS '语文',
  11. SUM(IF(subjectName='数学',score,0)) AS '数学',
  12. SUM(IF(subjectName='英语',score,0)) AS '英语',
  13. SUM(IF(subjectName='政治',score,0)) AS '政治',
  14. SUM(score) FROM tb_score;

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

  1. SET @EE='';
  2. select @EE :=CONCAT(@EE,'sum(if(subject= \'',subject,'\',score,0)) as ',subject, ',') AS aa FROM (SELECT DISTINCT subject FROM tb_score) A ;
  3. SET @QQ = CONCAT('select ifnull(userid,\'total\')as userid,',@EE,' sum(score) as total from tb_score group by userid WITH ROLLUP');
  4. -- SELECT @QQ;
  5. PREPARE stmt FROM @QQ;
  6. EXECUTE stmt;
  7. 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指定的列进行分组。

执行结果:

二、列转行

  1. CREATE TABLE tb_score1(
  2. id INT(11) NOT NULL auto_increment,
  3. userid VARCHAR(20) NOT NULL COMMENT '用户id',
  4. chinese_score DOUBLE COMMENT '语文成绩',
  5. math_score DOUBLE COMMENT '数学成绩',
  6. english_score DOUBLE COMMENT '英语成绩',
  7. politics_score DOUBLE COMMENT '政治成绩',
  8. PRIMARY KEY(id)
  9. )ENGINE = INNODB DEFAULT CHARSET = utf8;
  10. INSERT INTO tb_score1(userid,chinese_score,math_score,english_score,politics_score) VALUES ('001',90,92,80,0);
  11. INSERT INTO tb_score1(userid,chinese_score,math_score,english_score,politics_score) VALUES ('002',88,90,75.5,0);
  12. INSERT INTO tb_score1(userid,chinese_score,math_score,english_score,politics_score) VALUES ('003',70,85,90,82);
  13. INSERT INTO tb_score1(userid,chinese_score,math_score,english_score,politics_score) VALUES ('003',0,0,83,82);
  14. SELECT * FROM tb_score1;

查询结果:

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

  1. select userId,'语文' as subjectName,chinese_score as score from tb_score1
  2. union all
  3. select userId,'数学' as subjectName,math_score as score from tb_score1
  4. union all
  5. select userId,'英语' as subjectName,english_score as score from tb_score1
  6. union all
  7. select userId,'政治' as subjectName,politics_score as score from tb_score1;

转换后结果:

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

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

参考文章:

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

(0)

相关推荐