大家好,我是考100分的小小码 ,祝大家学习进步,加薪顺利呀。今天说一说MySQL实验–静态行转列->动态行转列->存储过程使用行转列「建议收藏」,希望您对编程的造诣更进一步.
概述
今天主要用一个实验来介绍一下在使用行转列的过程及相关实验。下面演示一下。
创建表
这里我用一个比较简单的例子来说明,也是行转列的经典例子,就是学生的成绩三张表:学生表、课程表、成绩表
1、学生表
就简单一点,学生学号、学生姓名两个字段
CREATE TABLE `student` ( `stuid` VARCHAR(16) NOT NULL COMMENT "学号", `stunm` VARCHAR(20) NOT NULL COMMENT "学生姓名", PRIMARY KEY (`stuid`) ) COLLATE="utf8_general_ci" ENGINE=InnoDB;
代码100分
2、课程表
课程编号、课程名
代码100分CREATE TABLE `courses` ( `courseno` VARCHAR(20) NOT NULL, `coursenm` VARCHAR(100) NOT NULL, PRIMARY KEY (`courseno`) ) COMMENT="课程表" COLLATE="utf8_general_ci" ENGINE=InnoDB;
3、成绩表
学生学号、课程号、成绩
CREATE TABLE `score` ( `stuid` VARCHAR(16) NOT NULL, `courseno` VARCHAR(20) NOT NULL, `scores` FLOAT NULL DEFAULT NULL, PRIMARY KEY (`stuid`, `courseno`) ) COLLATE="utf8_general_ci" ENGINE=InnoDB;
以上就是数据库表的结构了,这里没有建立外键,但是根据表的结构,可以清楚的看到成绩表中的学号和课程号是与学生表、课程表分别关联起来的。
基础数据准备
代码100分/*学生表数据*/ Insert Into student (stuid, stunm) Values("1001", "张三"); Insert Into student (stuid, stunm) Values("1002", "李四"); Insert Into student (stuid, stunm) Values("1003", "赵二"); Insert Into student (stuid, stunm) Values("1004", "王五"); Insert Into student (stuid, stunm) Values("1005", "刘青"); Insert Into student (stuid, stunm) Values("1006", "周明"); /*课程表数据*/ Insert Into courses (courseno, coursenm) Values("C001", "大学语文"); Insert Into courses (courseno, coursenm) Values("C002", "新视野英语"); Insert Into courses (courseno, coursenm) Values("C003", "离散数学"); Insert Into courses (courseno, coursenm) Values("C004", "概率论与数理统计"); Insert Into courses (courseno, coursenm) Values("C005", "线性代数"); Insert Into courses (courseno, coursenm) Values("C006", "高等数学(一)"); Insert Into courses (courseno, coursenm) Values("C007", "高等数学(二)"); /*成绩表数据*/ Insert Into score(stuid, courseno, scores) Values("1001", "C001", 67); Insert Into score(stuid, courseno, scores) Values("1002", "C001", 68); Insert Into score(stuid, courseno, scores) Values("1003", "C001", 69); Insert Into score(stuid, courseno, scores) Values("1004", "C001", 70); Insert Into score(stuid, courseno, scores) Values("1005", "C001", 71); Insert Into score(stuid, courseno, scores) Values("1006", "C001", 72); Insert Into score(stuid, courseno, scores) Values("1001", "C002", 87); Insert Into score(stuid, courseno, scores) Values("1002", "C002", 88); Insert Into score(stuid, courseno, scores) Values("1003", "C002", 89); Insert Into score(stuid, courseno, scores) Values("1004", "C002", 90); Insert Into score(stuid, courseno, scores) Values("1005", "C002", 91); Insert Into score(stuid, courseno, scores) Values("1006", "C002", 92); Insert Into score(stuid, courseno, scores) Values("1001", "C003", 83); Insert Into score(stuid, courseno, scores) Values("1002", "C003", 84); Insert Into score(stuid, courseno, scores) Values("1003", "C003", 85); Insert Into score(stuid, courseno, scores) Values("1004", "C003", 86); Insert Into score(stuid, courseno, scores) Values("1005", "C003", 87); Insert Into score(stuid, courseno, scores) Values("1006", "C003", 88); Insert Into score(stuid, courseno, scores) Values("1001", "C004", 88); Insert Into score(stuid, courseno, scores) Values("1002", "C004", 89); Insert Into score(stuid, courseno, scores) Values("1003", "C004", 90); Insert Into score(stuid, courseno, scores) Values("1004", "C004", 91); Insert Into score(stuid, courseno, scores) Values("1005", "C004", 92); Insert Into score(stuid, courseno, scores) Values("1006", "C004", 93); Insert Into score(stuid, courseno, scores) Values("1001", "C005", 77); Insert Into score(stuid, courseno, scores) Values("1002", "C005", 78); Insert Into score(stuid, courseno, scores) Values("1003", "C005", 79); Insert Into score(stuid, courseno, scores) Values("1004", "C005", 80); Insert Into score(stuid, courseno, scores) Values("1005", "C005", 81); Insert Into score(stuid, courseno, scores) Values("1006", "C005", 82); Insert Into score(stuid, courseno, scores) Values("1001", "C006", 77); Insert Into score(stuid, courseno, scores) Values("1002", "C006", 78); Insert Into score(stuid, courseno, scores) Values("1003", "C006", 79); Insert Into score(stuid, courseno, scores) Values("1004", "C006", 80); Insert Into score(stuid, courseno, scores) Values("1005", "C006", 81); Insert Into score(stuid, courseno, scores) Values("1006", "C006", 82);
测试数据
纵列效果
我们一般进行成绩查询的时候看到的是这种纵列的结果
mysql> select s.stuid,s.stunm,c.coursenm,sc.scores from student s,courses c ,score sc limit 20;
如果要把分数这一行跟课程这一列倒转怎么办呢?
静态行转列
Select st.stuid, st.stunm, MAX(CASE c.coursenm WHEN "大学语文" THEN s.scores ELSE 0 END ) "大学语文", MAX(CASE c.coursenm WHEN "新视野英语" THEN ifnull(s.scores,0) ELSE 0 END ) "新视野英语", MAX(CASE c.coursenm WHEN "离散数学" THEN ifnull(s.scores,0) ELSE 0 END ) "离散数学", MAX(CASE c.coursenm WHEN "概率论与数理统计" THEN ifnull(s.scores,0) ELSE 0 END ) "概率论与数理统计", MAX(CASE c.coursenm WHEN "线性代数" THEN ifnull(s.scores,0) ELSE 0 END ) "线性代数", MAX(CASE c.coursenm WHEN "高等数学(一)" THEN ifnull(s.scores,0) ELSE 0 END ) "高等数学(一)", MAX(CASE c.coursenm WHEN "高等数学(二)" THEN ifnull(s.scores,0) ELSE 0 END ) "高等数学(二)" From Student st Left Join score s On st.stuid = s.stuid Left Join courses c On c.courseno = s.courseno Group by st.stuid
看上面的语句可以看出,我们是在知道固定的几门课程之后,可以使用
MAX(CASE c.coursenm WHEN "线性代数" THEN ifnull(s.scores,0) ELSE 0 END ) "线性代数",
这样的语句来实现行转列
但课程不仅仅这几门,如果用上面的语句去写,第一要确定有多少课程,这么多课程的课程名要再拿出来,那样的话写一个查询语句下来,可是要写很多了。
动态行转列
如何进行动态行转列呢?首先我们要动态获取这样的语句
MAX(CASE c.coursenm WHEN "大学语文" THEN s.scores ELSE 0 END ) "大学语文", MAX(CASE c.coursenm WHEN "线性代数" THEN ifnull(s.scores,0) ELSE 0 END ) "线性代数", MAX(CASE c.coursenm WHEN "离散数学" THEN ifnull(s.scores,0) ELSE 0 END ) "离散数学"
而不是像上面那样一句句写出来,这里就要用到SQL语句拼接了。具体就是下面的语句
SELECT GROUP_CONCAT( DISTINCT CONCAT( "MAX(IF(c.coursenm = """, c.coursenm, """, s.scores, 0)) AS """, c.coursenm, """" ) ) FROM courses c;
上面就是进行行转列查询要用的语句,那样就不用知道多少课程和这些课程的名字,只要这样几行代码便可以得到动态的列了。
动态的列是拿到了,那如何再结合SQL语句进行查询得到结果呢?
这里要说明一点,因为用到了拼接函数,如果像上面的查询语句,只是把那几行语句替换掉,也就是下面这样
Select st.stuid, st.stunm, ( SELECT GROUP_CONCAT(DISTINCT CONCAT( "MAX(IF(c.coursenm = """, c.coursenm, """, s.scores, NULL)) AS ", c.coursenm ) ) FROM courses c ) From Student st Left Join score s On st.stuid = s.stuid Left Join courses c On c.courseno = s.courseno Group by st.stuid;
然而得到的结果却是这样的
最终结果如下:
像普通的那些语句那样进行声明,将语句拼接完整之后,再执行
--动态行转列 SET @SQL = NULL; SELECT GROUP_CONCAT( DISTINCT CONCAT( "MAX(IF(c.coursenm = """, c.coursenm, """, s.scores, 0)) AS """, c.coursenm, """" ) ) INTO @SQL FROM courses c; SET @SQL = CONCAT( "Select st.stuid, st.stunm, ", @SQL, " From Student st Left Join score s On st.stuid = s.stuid Left Join courses c On c.courseno = s.courseno Group by st.stuid" ); PREPARE stmt FROM @SQL; EXECUTE stmt; DEALLOCATE PREPARE stmt;
这样就实现了动态行转列的目的了。而且我们不用知道多少课程,也无需把这些课程名一一列出来。当然这个语句拼接中的查询可以加入条件查询。
存储过程–动态行转列
用存储过程的好处是,方便我们调用,相当于一个函数,其他可能也是类似的查询不需再重复写代码,直接调存储过程就好,还能随心所欲的加上if条件判断
创建存储过程的语句我就不多写了,这里把上面的查询语句直接放到创建存储过程的begin和end直接就可以了,如下:
DELIMITER && drop procedure if exists SP_QueryData; Create Procedure SP_QueryData(IN stuid varchar(16)) READS SQL DATA BEGIN SET @sql = NULL; SET @stuid = NULL; SELECT GROUP_CONCAT(DISTINCT CONCAT( "MAX(IF(c.coursenm = """, c.coursenm, """, s.scores, 0)) AS """, c.coursenm, """ ) ) INTO @sql FROM courses c; SET @sql = CONCAT("Select st.stuid, st.stunm, ", @sql, " From Student st Left Join score s On st.stuid = s.stuid Left Join courses c On c.courseno = s.courseno"); IF stuid is not null and stuid <> "" then SET @stuid = stuid; SET @sql = CONCAT(@sql, " Where st.stuid = "", @stuid, """); END IF; SET @sql = CONCAT(@sql, " Group by st.stuid"); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; END && DELIMITER ;
调用存储过程:
CALL `SP_QueryData`("1001");
得到如下结果
也可以直接传个空串过去
CALL `SP_QueryData`("");
同样得到我们想要的结果
总结
以上就是mysql数据库行转列实现的过程中的内容,耐心看完并认真研究的话,这个内容对你的行转列还是有很大帮助的。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/11145.html