MySQL 实现行转列SQL

MySQL 实现行转列SQL概述好久没写SQL语句,今天看到问答中的一个问题,拿来研究一下。问题链接:关于Mysql的分级输出问题情景简介学校里面记录成绩,每个人的选课不一样,而且以后会添加课程,所以不需要把所有课程当作列。数据表里面数据如下图,使用姓名+课程作为联合主键(有些需求可能不需要联合主键)。本文以MySQL为基础,其他数据库会有些许语法不同。数据库表数据:处理后的结果(行转列):方法一:这里可以使用Max,也可…

大家好,又见面了,我是你们的朋友全栈君。

概述

好久没写SQL语句,今天看到问答中的一个问题,拿来研究一下。

问题链接:关于Mysql 的分级输出问题

情景简介

学校里面记录成绩,每个人的选课不一样,而且以后会添加课程,所以不需要把所有课程当作列。数据表里面数据如下图,使用姓名+课程作为联合主键(有些需求可能不需要联合主键)。本文以MySQL为基础,其他数据库会有些许语法不同。

数据库表数据:

MySQL 实现行转列SQLMySQL 实现行转列SQL

处理后的结果(行转列):

MySQL 实现行转列SQL
MySQL 实现行转列SQL

方法一:

这里可以使用Max,也可以使用Sum;

注意第二张图,当有学生的某科成绩缺失的时候,输出结果为Null; 

[sql] 
view plain  
copy

  1. SELECT  
  2.     SNAME,  
  3.     MAX(  
  4.         CASE CNAME  
  5.         WHEN ‘JAVA’ THEN  
  6.             SCORE  
  7.         END  
  8.     ) JAVA,  
  9.     MAX(  
  10.         CASE CNAME  
  11.         WHEN ‘mysql’ THEN  
  12.             SCORE  
  13.         END  
  14.     ) mysql  
  15. FROM  
  16.     stdscore  
  17. GROUP BY  
  18.     SNAME;  



可以在第一个Case中加入Else语句解决这个问题:

[sql] 
view plain  
copy

  1. SELECT  
  2.     SNAME,  
  3.     MAX(  
  4.         CASE CNAME  
  5.         WHEN ‘JAVA’ THEN  
  6.             SCORE  
  7.         ELSE  
  8.             0  
  9.         END  
  10.     ) JAVA,  
  11.     MAX(  
  12.         CASE CNAME  
  13.         WHEN ‘mysql’ THEN  
  14.             SCORE  
  15.         ELSE  
  16.             0  
  17.         END  
  18.     ) mysql  
  19. FROM  
  20.     stdscore  
  21. GROUP BY  
  22.     SNAME;  

方法二:

[sql] 
view plain  
copy

  1. SELECT DISTINCT  a.sname,  
  2. (SELECT score FROM stdscore b WHERE a.sname=b.sname AND b.CNAME=‘JAVA’ ) AS ‘JAVA’,  
  3. (SELECT score FROM stdscore b WHERE a.sname=b.sname AND b.CNAME=‘mysql’ ) AS ‘mysql’  
  4. FROM stdscore a  



方法三:

[sql] 
view plain  
copy

  1. DROP PROCEDURE  
  2. IF EXISTS sp_score;  
  3. DELIMITER &&  
  4.   
  5. CREATE PROCEDURE sp_score ()  
  6. BEGIN  
  7.     #课程名称  
  8.     DECLARE  
  9.         cname_n VARCHAR (20) ; #所有课程数量  
  10.         DECLARE  
  11.             count INT ; #计数器  
  12.             DECLARE  
  13.                 i INT DEFAULT 0 ; #拼接SQL字符串  
  14.             SET @s = ‘SELECT sname’ ;  
  15.             SET count = (  
  16.                 SELECT  
  17.                     COUNT(DISTINCT cname)  
  18.                 FROM  
  19.                     stdscore  
  20.             ) ;  
  21.             WHILE i < count DO  
  22.   
  23.   
  24.             SET cname_n = (  
  25.                 SELECT  
  26.                     cname  
  27.                 FROM  
  28.                     stdscore  
  29.                 GROUP BY CNAME   
  30.                 LIMIT i,  
  31.                 1  
  32.             ) ;  
  33.             SET @s = CONCAT(  
  34.                 @s,  
  35.                 ‘, SUM(CASE cname WHEN ‘,  
  36.                 ‘\”,  
  37.                 cname_n,  
  38.                 ‘\”,  
  39.                 ‘ THEN score ELSE 0 END)’,  
  40.                 ‘ AS ‘,  
  41.                 ‘\”,  
  42.                 cname_n,  
  43.                 ‘\”  
  44.             ) ;  
  45.             SET i = i + 1 ;  
  46.             END  
  47.             WHILE ;  
  48.             SET @s = CONCAT(  
  49.                 @s,  
  50.                 ‘ FROM stdscore GROUP BY sname’  
  51.             ) ; #用于调试  
  52.             #SELECT @s;  
  53.             PREPARE stmt  
  54.             FROM  
  55.                 @s ; EXECUTE stmt ;  
  56.             END&&  
  57.   
  58. CALL sp_score () ;  


处理后的结果(行转列)分级输出:

MySQL 实现行转列SQL
MySQL 实现行转列SQL




方法一:

这里可以使用Max,也可以使用Sum;

注意第二张图,当有学生的某科成绩缺失的时候,输出结果为Null; 

[sql] 
view plain  
copy

  1. SELECT  
  2.     SNAME,  
  3.     MAX(  
  4.         CASE CNAME  
  5.         WHEN ‘JAVA’ THEN  
  6.             (  
  7.                 CASE  
  8.                 WHEN SCORE – (select avg(SCORE) from stdscore where CNAME=‘JAVA’) > 20 THEN  
  9.                     ‘优秀’  
  10.                 WHEN SCORE – (select avg(SCORE) from stdscore where CNAME=‘JAVA’) > 10 THEN  
  11.                     ‘良好’  
  12.                 WHEN SCORE – (select avg(SCORE) from stdscore where CNAME=‘JAVA’) >= 0 THEN  
  13.                     ‘普通’  
  14.                 ELSE  
  15.                     ‘较差’  
  16.                 END  
  17.             )  
  18.         END  
  19.     ) JAVA,  
  20.     MAX(  
  21.         CASE CNAME  
  22.         WHEN ‘mysql’ THEN  
  23.             (  
  24.                 CASE  
  25.                 WHEN SCORE – (select avg(SCORE) from stdscore where CNAME=‘JAVA’) > 20 THEN  
  26.                     ‘优秀’  
  27.                 WHEN SCORE – (select avg(SCORE) from stdscore where CNAME=‘JAVA’) > 10 THEN  
  28.                     ‘良好’  
  29.                 WHEN SCORE – (select avg(SCORE) from stdscore where CNAME=‘JAVA’) >= 0 THEN  
  30.                     ‘普通’  
  31.                 ELSE  
  32.                     ‘较差’  
  33.                 END  
  34.             )  
  35.         END  
  36.     ) mysql  
  37. FROM  
  38.     stdscore  
  39. GROUP BY  
  40.     SNAME;  



方法二:

[sql] 
view plain  
copy

  1. SELECT DISTINCT  a.sname,  
  2. (SELECT (  
  3.                 CASE  
  4.                 WHEN SCORE – (select avg(SCORE) from stdscore where CNAME=‘JAVA’) > 20 THEN  
  5.                     ‘优秀’  
  6.                 WHEN SCORE – (select avg(SCORE) from stdscore where CNAME=‘JAVA’) > 10 THEN  
  7.                     ‘良好’  
  8.                 WHEN SCORE – (select avg(SCORE) from stdscore where CNAME=‘JAVA’) >= 0 THEN  
  9.                     ‘普通’  
  10.                 ELSE  
  11.                     ‘较差’  
  12.                 END  
  13.             ) FROM stdscore b WHERE a.sname=b.sname AND b.CNAME=‘JAVA’ ) AS ‘JAVA’,  
  14. (SELECT (  
  15.                 CASE  
  16.                 WHEN SCORE – (select avg(SCORE) from stdscore where CNAME=‘JAVA’) > 20 THEN  
  17.                     ‘优秀’  
  18.                 WHEN SCORE – (select avg(SCORE) from stdscore where CNAME=‘JAVA’) > 10 THEN  
  19.                     ‘良好’  
  20.                 WHEN SCORE – (select avg(SCORE) from stdscore where CNAME=‘JAVA’) >= 0 THEN  
  21.                     ‘普通’  
  22.                 ELSE  
  23.                     ‘较差’  
  24.                 END  
  25.             ) FROM stdscore b WHERE a.sname=b.sname AND b.CNAME=‘mysql’ ) AS ‘mysql’  
  26. FROM stdscore a  



方法三:

[sql] 
view plain  
copy

  1. DROP PROCEDURE  
  2. IF EXISTS sp_score;  
  3. DELIMITER &&  
  4.   
  5. CREATE PROCEDURE sp_score ()  
  6. BEGIN  
  7.     #课程名称  
  8.     DECLARE  
  9.         cname_n VARCHAR (20) ; #所有课程数量  
  10.         DECLARE  
  11.             count INT ; #计数器  
  12.             DECLARE  
  13.                 i INT DEFAULT 0 ; #拼接SQL字符串  
  14.             SET @s = ‘SELECT sname’ ;  
  15.             SET count = (  
  16.                 SELECT  
  17.                     COUNT(DISTINCT cname)  
  18.                 FROM  
  19.                     stdscore  
  20.             ) ;  
  21.             WHILE i < count DO  
  22.   
  23.   
  24.             SET cname_n = (  
  25.                 SELECT  
  26.                     cname  
  27.                 FROM  
  28.                     stdscore  
  29.         GROUP BY CNAME   
  30.                 LIMIT i, 1  
  31.             ) ;  
  32.             SET @s = CONCAT(  
  33.                 @s,  
  34.                 ‘, MAX(CASE cname WHEN ‘,  
  35.                 ‘\”,  
  36.                 cname_n,  
  37.                 ‘\”,  
  38.                 ‘ THEN (  
  39.                 CASE  
  40.                 WHEN SCORE – (select avg(SCORE) from stdscore where CNAME=\,cname_n,‘\’) > 20 THEN  
  41.                     \‘优秀\’  
  42.                 WHEN SCORE – (select avg(SCORE) from stdscore where CNAME=\,cname_n,‘\’) > 10 THEN  
  43.                     \‘良好\’  
  44.                 WHEN SCORE – (select avg(SCORE) from stdscore where CNAME=\,cname_n,‘\’) >= 0 THEN  
  45.                     \‘普通\’  
  46.                 ELSE  
  47.                     \‘较差\’  
  48.                 END  
  49.             ) END)’,  
  50.                 ‘ AS ‘,  
  51.                 ‘\”,  
  52.                 cname_n,  
  53.                 ‘\”  
  54.             ) ;  
  55.             SET i = i + 1 ;  
  56.             END  
  57.             WHILE ;  
  58.             SET @s = CONCAT(  
  59.                 @s,  
  60.                 ‘ FROM stdscore GROUP BY sname’  
  61.             ) ;   
  62.             #用于调试  
  63.             #SELECT @s;  
  64.             PREPARE stmt  
  65.             FROM  
  66.                 @s ; EXECUTE stmt ;  
  67.             END&&  
  68.   
  69.   
  70. CALL sp_score ();  

几种方法比较分析

第一种使用了分组,对每个课程分别处理。

第二种方法使用了表连接。

第三种使用了存储过程,实际上可以是第一种或第二种方法的动态化,先计算出所有课程的数量,然后对每个分组进行课程查询。
这种方法的一个最大的好处是当新增了一门课程时,SQL语句不需要重写。

小结

关于行转列和列转行

这个概念似乎容易弄混,有人把行转列理解为列转行,有人把列转行理解为行转列;

这里做个定义:

行转列:把表中特定列(如本文中的:CNAME)的数据去重后做为列名(如查询结果行中的“Java,mysql”,处理后是做为列名输出);

列转行:可以说是行转列的反转,把表中特定列(如本文处理结果中的列名“JAVA,mysql”)做为每一行数据对应列“CNAME”的值;

关于效率

不知道有什么好的生成模拟数据的方法或工具,麻烦小伙伴推荐一下,抽空我做一下对比;

还有其它更好的方法吗?

本文使用的几种方法应该都有优化的空间,特别是使用存储过程的话会更加灵活,功能更强大;

本文的分级只是给出一种思路,分级的方法如果学生的成绩相差较小的话将失去意义;

如果小伙伴有更好的方法,还请不吝赐教,感激不尽!

有些需求可能不需要联合主键

有些需求可能不需要联合主键,因为一门课程可能允许学生考多次,取最好的一次成绩,或者取多次的平均成绩。


原文地址:
http://blog.csdn.net/testcs_dn/article/details/49847299

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/132379.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 学会使用getopt函数[通俗易懂]

    学会使用getopt函数[通俗易懂]简介getopt函数是命令行参数解析函数,在平时阅读源码的时候经常遇到,很有必要对其总结一下,做个记录!命令行参数各组成部分的名称先来了解下命令行参数各组成部分的名称。直接上图:非常清楚,命令行参数由Commandname,Option,Optionargument以及Operands组成。Commandname不用多说,就是程序的名称。操作对象Operands又…

    2022年6月9日
    48
  • java 接口学习

    你应该知道接口是一种契约,它与实现方式无关但是类,即使是抽象类,你都能自定义成员变量,而成员变量往往就与实现方式有关。这一点的实际意义不大。但是有一点,类会暴露太多不必要,甚至不能暴露的东西,你

    2021年12月22日
    49
  • OpenCV图像几何变换专题(缩放、翻转、仿射变换及透视)【python-Open_CV系列(五)】

    OpenCV图像几何变换专题(缩放、翻转、仿射变换及透视)【python-Open_CV系列(五)】OpenCV图像几何变换(python为工具)Open_CV系列(五)准备图片1.缩放cv2.resize()方法2.翻转cv2.flip()方法3.仿射变换warpAffine()方法3.1平移3.2旋转3.3倾斜4.透视

    2025年6月3日
    2
  • php网页设计导航栏代码,总结7种常见的导航条制作实例

    php网页设计导航栏代码,总结7种常见的导航条制作实例导航条是网页设计中不可缺少的部分,它是指通过一定的技术手段,为网站的访问者提供一定的途径,使其可以方便地访问到所需的内容,是人们浏览网站时可以快速从一个页面转到另一个页面的快速通道。利用导航条,我们就可以快速找到我们想要浏览的页面。今天分享一下简单导航栏的制作方法:第一步:引入css样式表,新建一个id为nav的层,使用、、标签来制作完成效果。这篇文章主要为大家详细介绍了微信小程序实战之顶部导航栏…

    2022年7月22日
    15
  • 基尼系数excel计算方法_excel计算基尼系数步骤

    基尼系数excel计算方法_excel计算基尼系数步骤我真的是个计算基尼系数的小能手,在excel、python、hive上都凑齐了。。。excel如下图所示:第一行显示的是,该列标黄色框内的公式。

    2022年10月13日
    2
  • 基于Deep Learning 的视频识别技术「建议收藏」

    基于Deep Learning 的视频识别技术「建议收藏」深度学习在最近十来年特别火,几乎是带动AI浪潮的最大贡献者。互联网视频在最近几年也特别火,短视频、视频直播等各种新型UGC模式牢牢抓住了用户的消费心里,成为互联网吸金的又一利器。当这两个火碰在一起,会产生什么样的化学反应呢?不说具体的技术,先上一张福利图,该图展示了机器对一个视频的认知效果。其总红色的字表示objects,蓝色的字表示scen…

    2022年5月27日
    25

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号