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

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

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • Java的异常处理机制

    Java的异常处理机制一、什么是java异常?java异常指在程序运行时可能出现的一些错误,如:文件找不到、网络连接失败、非法参数等。异常是一个事件,它发生在程序运行期间,中断了正在执行的程序的正常指令流。Java通过API中Throwable类的众多子类描述各种不同的异常。因而,Java异常都是对象,是Throwable子类的实例,描述了出现在一段编码中的错误条件。当条件生成时,错误将引发异常。Java异常类…

  • 一文详解蒙特卡洛(Monte Carlo)法及其应用

    一文详解蒙特卡洛(Monte Carlo)法及其应用我的机器学习教程「美团」算法工程师带你入门机器学习已经开始更新了,欢迎大家订阅~任何关于算法、编程、AI行业知识或博客内容的问题,可以随时扫码关注公众号「图灵的猫」,加入”学习小组“,沙雕博主在线答疑~此外,公众号内还有更多AI、算法、编程和大数据知识分享,以及免费的SSR节点和学习资料。其他平台(知乎/B站)也是同名「图灵的猫」,不要迷路哦~概述…

  • N70常用软件大集合

    N70常用软件大集合管理软件[文件管理]SmartFilemanv1.03汉化版[进程管理]AppManv1.04完美简体中文优化MMC绿色版[文件管理]SystemExplorerv1.8汉化版[程序管理]Fexplorerv1.15完美汉化完全版《N70拨号大字体》+《N70解决opera8.5上网一些地方显示口口的字体》英文机N70用的完美中文字体[压缩工具]解压利器zipman2.

  • HTML 表格表单代码实例(个人简介表)

    HTML 表格表单代码实例(个人简介表)<!DOCTYPEhtml><htmllang=”en”><head><metacharset=”UTF-8″><metahttp-equiv=”X-UA-Compatible”content=”IE=edge”><metaname=”viewport”content=”width=device-width,initial-scale=1.0″><title&…

  • 论.idea文件夹是干嘛的「建议收藏」

    论.idea文件夹是干嘛的「建议收藏」Problempython为什么每次创建的文件目录下都含.idea/文件夹?该文件夹又是用来干嘛的?Answer当使用pycharm作为IDE时,会自动生成.idea/文件夹来存放项目的配置信息。其中包括版本控制信息、历史记录等等。…

  • mysql executereader_C# 操作MySQL数据库, ExecuteReader()方法参数化执行T-SQL语句, 游标读取数据…

    mysql executereader_C# 操作MySQL数据库, ExecuteReader()方法参数化执行T-SQL语句, 游标读取数据…C#操作MySQL数据库需要引用”MySql.Data”,可通过两种方式获取。1、从NuGet下载”Install-PackageMySql.Data-Version6.8.7″推荐使用方式一,从NuGet上直接获取所需dll,方便快捷。C#操作MySQL数据库,ExecuteReader()方法参数化执行T-SQL语句,游标读取数据–ExecuteNonQuery()对连接执…

发表回复

您的电子邮箱地址不会被公开。

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