mysql行列转置
将一个数据表行列转置,有几种方法?有很多,不过今天我只介绍其中最常用的 3 种。案例:将下图 1 中的 B 列行列转置,效果如下图 2 所示。解决方案 1:复制粘贴1. 选中 B1:B6 区域 -->...
2024.11.12今天主要用一个实验来介绍一下在使用行转列的过程及相关实验。下面演示一下。
创建表这里我用一个比较简单的例子来说明,也是行转列的经典例子,就是学生的成绩三张表:学生表、课程表、成绩表
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;2、课程表
课程编号、课程名
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;以上就是数据库表的结构了,这里没有建立外键,但是根据表的结构,可以清楚的看到成绩表中的学号和课程号是与学生表、课程表分别关联起来的。
基础数据准备/*学生表数据*/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 stLeft Join score s On st.stuid = s.stuidLeft Join courses c On c.courseno = s.coursenoGroup 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语句拼接了。具体就是下面的语句
selectGROUP_CONCAT( DISTINCT concat( ‘MAX(IF(c.coursenm = ‘‘‘, c.coursenm, ‘‘‘, s.scores, 0)) AS ‘‘‘, c.coursenm, ‘‘‘‘ ) ) FROMcourses 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 stLeft Join score s On st.stuid = s.stuidLeft Join courses c On c.courseno = s.coursenoGroup by st.stuid;然而得到的结果却是这样的
最终结果如下:
像普通的那些语句那样进行声明,将语句拼接完整之后,再执行
--动态行转列SET @SQL = NULL;selectGROUP_CONCAT( DISTINCT concat( ‘MAX(IF(c.coursenm = ‘‘‘, c.coursenm, ‘‘‘, s.scores, 0)) AS ‘‘‘, c.coursenm, ‘‘‘‘ ) ) INTO @SQL FROMcourses c; SET @SQL = concat( ‘select st.stuid, st.stunm, ‘, @SQL, ‘ From Student st Left Join score s On st.stuid = s.stuidLeft Join courses c On c.courseno = s.coursenoGroup 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 @sqlFROM 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 ‘‘ thenSET @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数据库行转列实现的过程中的内容,相对来说,我觉得,这里写的很清晰了,所以只要你有耐心看完并认真研究的话,这个内容对你的行转列还是有很大帮助的,建议大家百忙之中做下实验。后面会分享更多DBA方面的内容,感兴趣的朋友可以关注一下~
将一个数据表行列转置,有几种方法?有很多,不过今天我只介绍其中最常用的 3 种。案例:将下图 1 中的 B 列行列转置,效果如下图 2 所示。解决方案 1:复制粘贴1. 选中 B1:B6 区域 -->...
2024.11.12概述今天主要做一个实验,先理解下mysql行列转换,后面在做一下反向的行列转换。需求二维关系转换为三维关系。1、环境准备create database test;use test;create tab...
2024.11.15作者:杨文DBA,负责客户项目的需求与维护,会点数据库,不限于MySQL、Redis、Cassandra、GreenPlum、ClickHouse、Elastic、TDSQL等等。本文来源:原创投稿*...
2024.11.15邮件发送原理telnet命令模拟邮件发送:1、cmd命令下telnet连接上QQ的smtp服务器telnet smtp.163.com 25遇到问题以及解决办法:telnet命令错误控制面板下wind...
2024.11.15创建学生表create table t_student(id intauto_increment primary key ,city_no varchar(30),city_name varchar(...
2024.11.15