一文弄懂MYSQL如何列转行

目录
  • 一、需求:
  • 二、如何实现
    • 1)首先看我们的静态SQL
    • 2)那么就有人问了,如果我有100门课程不是要写100次名称,这也太麻烦了?
    • 3)这样每次都写一长串sql也很麻烦?
  • 总结

一、需求:

有三张表,学生表、成绩表和课程表,我们可以通过连表查询出学生姓名、课程及对应的成绩: 所需表sql

-- ----------------------------
-- Table structure for student
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
  `s_id` varchar(20) NOT NULL DEFAULT '',
  `s_name` varchar(20) NOT NULL DEFAULT '',
  `s_birth` varchar(20) NOT NULL DEFAULT '',
  `s_sex` varchar(10) NOT NULL DEFAULT '',
  PRIMARY KEY (`s_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of student
-- ----------------------------
INSERT INTO `student` VALUES ('01', '赵雷', '1990-01-01', '男');
INSERT INTO `student` VALUES ('02', '钱电', '1990-12-21', '男');
INSERT INTO `student` VALUES ('03', '孙风', '1990-05-20', '男');
INSERT INTO `student` VALUES ('04', '李云', '1990-08-06', '男');
INSERT INTO `student` VALUES ('05', '周梅', '1991-12-01', '女');
INSERT INTO `student` VALUES ('06', '吴兰', '1992-03-01', '女');
INSERT INTO `student` VALUES ('07', '郑竹', '1989-07-01', '女');
INSERT INTO `student` VALUES ('08', '王菊', '1990-01-20', '女');

-- ----------------------------
-- Table structure for course
-- ----------------------------
DROP TABLE IF EXISTS `course`;
CREATE TABLE `course` (
  `c_id` varchar(20) NOT NULL DEFAULT '',
  `c_name` varchar(20) NOT NULL DEFAULT '',
  `t_id` varchar(20) NOT NULL,
  PRIMARY KEY (`c_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of course
-- ----------------------------
INSERT INTO `course` VALUES ('01', '语文', '02');
INSERT INTO `course` VALUES ('02', '数学', '01');
INSERT INTO `course` VALUES ('03', '英语', '03');

-- ----------------------------
-- Table structure for score
-- ----------------------------
DROP TABLE IF EXISTS `score`;
CREATE TABLE `score` (
  `s_id` varchar(20) NOT NULL DEFAULT '',
  `c_id` varchar(20) NOT NULL DEFAULT '',
  `s_score` int(3) DEFAULT NULL,
  PRIMARY KEY (`s_id`,`c_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of score
-- ----------------------------
INSERT INTO `score` VALUES ('01', '01', '80');
INSERT INTO `score` VALUES ('01', '02', '90');
INSERT INTO `score` VALUES ('01', '03', '99');
INSERT INTO `score` VALUES ('02', '01', '70');
INSERT INTO `score` VALUES ('02', '02', '60');
INSERT INTO `score` VALUES ('02', '03', '80');
INSERT INTO `score` VALUES ('03', '01', '80');
INSERT INTO `score` VALUES ('03', '02', '80');
INSERT INTO `score` VALUES ('03', '03', '80');
INSERT INTO `score` VALUES ('04', '01', '50');
INSERT INTO `score` VALUES ('04', '02', '30');
INSERT INTO `score` VALUES ('04', '03', '20');
INSERT INTO `score` VALUES ('05', '01', '76');
INSERT INTO `score` VALUES ('05', '02', '87');
INSERT INTO `score` VALUES ('06', '01', '31');
INSERT INTO `score` VALUES ('06', '03', '34');
INSERT INTO `score` VALUES ('07', '02', '89');
INSERT INTO `score` VALUES ('07', '03', '98');
SELECT s.s_id,s.s_name,c.c_name,sc.s_score
FROM student s
LEFT JOIN score sc on sc.s_id = s.s_id
LEFT JOIN course c on c.c_id = sc.c_id

好的,现在呢我们要把课程名称呢变成横行呢?

二、如何实现

1)首先看我们的静态SQL

关联成绩表课程表查询学生各科课程成绩

SELECT s.s_id,s.s_name,c.c_name,sc.s_score
FROM student s
LEFT JOIN score sc on sc.s_id=s.s_id
LEFT JOIN course c on c.c_id = sc.c_id;

IF(s1,s2,s3)表达式,类似三木运算符取值,s1值为真取s2值,假取s3个值,最后可得到某一科成绩

SELECT  p.s_id,p.s_name, p.c_name,p.c_name = '数学',
IF(p.c_name = '数学',p.c_name,NULL)c_name,IF(p.c_name = '数学',p.s_score,NULL)s_score
FROM (
	SELECT s.s_id,s.s_name,c.c_name,sc.s_score
	FROM student s
	LEFT JOIN score sc on sc.s_id=s.s_id
	LEFT JOIN course c on c.c_id = sc.c_id	)p;

然后我们分组且用MAX函数获取每个学生的数学课程的成绩,替换这一课的字段名称

SELECT  p.s_id,
        p.s_name,
        MAX(IF(p.c_name = '数学', p.s_score, NULL)) AS 数学
FROM (
	SELECT s.s_id,s.s_name,c.c_name,sc.s_score
	FROM student s
	LEFT JOIN score sc on sc.s_id=s.s_id
	LEFT JOIN course c on c.c_id = sc.c_id	)p
GROUP BY p.s_id;

获取所有人各科成绩

SELECT  p.s_id,
        p.s_name,
        MAX(IF(p.c_name = '数学', p.s_score, NULL)) AS 数学,
        MAX(IF(p.c_name = '语文', p.s_score, NULL)) AS 语文,
        MAX(IF(p.c_name = '英语', p.s_score, NULL)) AS 英语
FROM (
	SELECT s.s_id,s.s_name,c.c_name,sc.s_score
	FROM student s
	LEFT JOIN score sc on sc.s_id=s.s_id
	LEFT JOIN course c on c.c_id = sc.c_id	)p
GROUP BY p.s_id;

2)那么就有人问了,如果我有100门课程不是要写100次名称,这也太麻烦了?

接下来请看动态SQL

我们的动态sql是拼接实现的, 主要就是拼接我们的课程成绩那一句, 所以要先看一下CONCAT函数拼接课程语句

SELECT c_name,CONCAT( 'MAX(IF(p.c_name = ''', c_name, ''', c.s_score, NULL)) AS ', c_name ) FROM course c;

是的,结果就是上面要的MAX函数

然后我么可以用GROUP_CONCAT()函数把这些内容拼接成一句

SELECT GROUP_CONCAT(DISTINCT c_name,CONCAT( 'MAX(IF(p.c_name = ''', c_name, ''', c.s_score, NULL)) AS ', c_name )) FROM course c;

接下来,拼接sql实现需求

-- 1.定义一个sql变量
SET @sql = NULL;

-- 2.把我们的查询课程的sql赋给变量
SELECT GROUP_CONCAT(DISTINCT CONCAT('MAX(IF(p.c_name = ''',c_name,''', p.s_score, NULL)) AS ',c_name)) INTO @sql
FROM course;

-- 3.拼接sql
SET @sql = CONCAT('SELECT  p.s_id, p.s_name, ', @sql ,'
			FROM (SELECT s.s_id,s.s_name,c.c_name,sc.s_score
			FROM student s
			LEFT JOIN score sc on sc.s_id=s.s_id
			LEFT JOIN course c on c.c_id = sc.c_id)p
			GROUP BY p.s_id');

-- 预处理语句
PREPARE stmt FROM @sql;
-- 执行
EXECUTE stmt;
-- 销毁
DEALLOCATE PREPARE stmt;

3)这样每次都写一长串sql也很麻烦?

好的 那么我们来封装成存储过程

-- 1、创建无参存储过程
delimiter $$
CREATE PROCEDURE getStudentRow()
BEGIN
    ------把要执行的sql放在这里就可以了
		SET @sql = NULL;
		SELECT
        GROUP_CONCAT(DISTINCT CONCAT('MAX(IF(p.c_name = ''',c_name,''', p.s_score, NULL)) AS ',c_name))
        INTO @sql FROM course;
    SET @sql = CONCAT('SELECT  p.s_id, p.s_name, ', @sql ,'
    	FROM (SELECT s.s_id,s.s_name,c.c_name,sc.s_score
    	FROM student s
    	LEFT JOIN score sc on sc.s_id=s.s_id
    	LEFT JOIN course c on c.c_id = sc.c_id)p
    	GROUP BY p.s_id');
    PREPARE stmt FROM @sql;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;
    ------把要执行的sql放在这里就可以了
END$$;
delimiter;

-- 查询存储过程
SHOW PROCEDURE STATUS;

-- 调用
CALL getStudentRow();

这样每次直接调用就可以了?

总结

到此这篇关于MYSQL如何列转行的文章就介绍到这了,更多相关MYSQL列转行内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • mysql 列转行的技巧(分享)

    前言: 由于很多业务表因为历史原因或者性能原因,都使用了违反第一范式的设计模式.即同一个列中存储了多个属性值(具体结构见下表). 这种模式下,应用常常需要将这个列依据分隔符进行分割,并得到列转行的结果. 表数据: ID Value 1 tiny,small,big 2 small,medium 3 tiny,big 期望得到结果: ID Value 1 tiny 1 small 1 big 2 small 2 medium 3 tiny 3 big 正文: #需要处理的表 create tabl

  • mysql列转行以及年月分组实例

    如下所示: SELECT count(DISTINCT(a.rect_id)) zcount, a.job_dept,  DATE_FORMAT(submit_date, '%Y-%m') zsubmit_date  FROM  表名 a  WHERE  a.statu = 3  AND a.rstatu = 2  AND a.job_dept IN ('19', '20', '21')  GROUP BY  a.job_dept,  DATE_FORMAT(submit_date, '%Y-%

  • mysql 行转列和列转行实例详解

    mysql行转列.列转行 语句不难,不做多余解释了,看语句时,从内往外一句一句剖析 行转列 有如图所示的表,现在希望查询的结果将行转成列 建表语句如下: CREATE TABLE `TEST_TB_GRADE` ( `ID` int(10) NOT NULL AUTO_INCREMENT, `USER_NAME` varchar(20) DEFAULT NULL, `COURSE` varchar(20) DEFAULT NULL, `SCORE` float DEFAULT '0', PRIM

  • mysql 列转行,合并字段的方法(必看)

    数据表: 列转行:利用max(case when then) max---聚合函数 取最大值 (case course when '语文' then score else 0 end) ---判断 as 语文---别名作为列名 SELECT `name`, MAX( CASE WHEN course='语文' THEN score END ) AS 语文, MAX( CASE WHEN course='数学' THEN score END ) AS 数学, MAX( CASE WHEN cour

  • 一文弄懂MYSQL如何列转行

    目录 一.需求: 二.如何实现 1)首先看我们的静态SQL 2)那么就有人问了,如果我有100门课程不是要写100次名称,这也太麻烦了? 3)这样每次都写一长串sql也很麻烦? 总结 一.需求: 有三张表,学生表.成绩表和课程表,我们可以通过连表查询出学生姓名.课程及对应的成绩: 所需表sql -- ---------------------------- -- Table structure for student -- ---------------------------- DROP TA

  • 一文弄懂MySQL索引创建原则

    目录 一.适合创建索引 1.字段的数值有唯一性限制 2.频繁作为Where查询条件的字段 3.经常Groupby和Orderby的列 4.Update.Delete的where条件列 5.Distinct字段需要创建索引 6.多表Join连接操作时,创建索引注意事项 7.使用列的类型小的创建索引 8.使用字符串前缀创建索引 9.区分度高的列适合作为索引 10.使用最频繁的列放到联合索引的左侧 11.在多个字段都要创建索引的情况下,联合索引由于单值索引 二.不适合创建索引 1.在where中使用不

  • 一文弄懂MySQL中redo log与binlog的区别

    目录 前言 1. 什么是redo log? 1.1 redo日志文件名 1.2 影响redo log参数 1.3 redo log大小怎么设置? 2. 什么是binlog 2.1 binlog文件名 2.2 影响binlog的参数 2.3 查看binlog 3. redo log与binlog的区别 总结 前言 MySQL中有六种日志文件,分别是:重做日志(redo log).回滚日志(undo log).二进制日志(binlog).错误日志(errorlog).慢查询日志(slow query

  • 一篇文章弄懂MySQL查询语句的执行过程

    前言 需要从数据库检索某些符合要求的数据,我们很容易写出 Select A B C FROM T WHERE ID = XX  这样的SQL,那么当我们向数据库发送这样一个请求时,数据库到底做了什么? 我们今天以MYSQL为例,揭示一下MySQL数据库的查询过程,并让大家对数据库里的一些零件有所了解. MYSQL架构 mysql架构 MySQL 主要可以分为 Server 层和存储引擎层. Server层 包括连接器.查询缓存.分析器.优化器.执行器等,所有跨存储引擎的功能都在这一层实现,比如存

  • 一文搞懂MySQL持久化和回滚的原理

    目录 redo log 为什么要先更新内存数据,不直接更新磁盘数据? 为什么需要redo log? redo log是如何实现的? 为什么一个block设计成512字节? 为什么要两段式提交? crash后是如何恢复的? undo log 什么情况下会生成undo log? undo log是如何回滚的? undo log存在什么地方? redo log 事务的支持是数据库区分文件系统的重要特征之一,事务的四大特性: 原子性:所有的操作要么都做,要么都不做,不可分割. 一致性:数据库从一种状态变

  • 一文读懂MySQL 表分区

    目录 1. 什么是表分区 2. 分区的两种方式 2.1 水平切分 2.2 垂直切分 3. 为什么需要表分区 4. 分区实践 4.1 RANGE 分区 4.2 LIST 分区 4.3 HASH 分区 4.4 KEY 分区 4.5 COLUMNS 分区 5. 常见分区命令 6. 小结 松哥之前写过文章跟大家介绍过用 MyCat 实现 MySQL 的分库分表,不知道有没有小伙伴研究过,MySQL 其实也自带了分区功能,我们可以创建一个带有分区的表,而且不需要借助任何外部工具,今天我们就一起来看看. 1

  • 一文搞懂MySQL元数据锁(MDL)

    目录 一.什么是metadata lock 二.MDL和行锁有什么区别 三.MDL为什么会造成系统崩溃 四.MDL的生命周期有多长 五.如何快速找到阻塞源头 六.本文开始的案例最终如何解决 小结 某日,路上收到用户咨询,为了清除空间,想删除某200多G大表数据,且已经确认此表不再有业务访问,于是执行了一条命令‘delete from bigtable’,但好长时间也没删完,经过咨询后,获知drop table删除表速度快,而且能彻底释放空间,于是又在另外一个session中执行了‘drop ta

  • 一文搞懂MySQL预编译

    1.预编译的好处 大家平时都使用过JDBC中的PreparedStatement接口,它有预编译功能.什么是预编译功能呢?它有什么好处呢? 当客户发送一条SQL语句给服务器后,服务器总是需要校验SQL语句的语法格式是否正确,然后把SQL语句编译成可执行的函数,最后才是执行SQL语句.其中校验语法,和编译所花的时间可能比执行SQL语句花的时间还要多. 如果我们需要执行多次insert语句,但只是每次插入的值不同,MySQL服务器也是需要每次都去校验SQL语句的语法格式,以及编译,这就浪费了太多的时

  • 一文弄懂Pytorch的DataLoader, DataSet, Sampler之间的关系

    以下内容都是针对Pytorch 1.0-1.1介绍. 很多文章都是从Dataset等对象自下往上进行介绍,但是对于初学者而言,其实这并不好理解,因为有的时候会不自觉地陷入到一些细枝末节中去,而不能把握重点,所以本文将会自上而下地对Pytorch数据读取方法进行介绍. 自上而下理解三者关系 首先我们看一下DataLoader.next的源代码长什么样,为方便理解我只选取了num_works为0的情况(num_works简单理解就是能够并行化地读取数据). class DataLoader(obje

  • 一文搞懂MySQL XA如何实现分布式事务

    目录 前言 XA 协议 如何通过MySQL XA实现分布式事务 前言 MySQL支持单机事务的良好表现毋庸置疑,那么在分布式系统中,涉及多个节点,MySQL又是如何实现分布式事务的呢?比如开发一个业务系统,它接受外部的请求,然后访问多个内部其它系统才能执行该请求.执行时我们需要同时更新多个数据库的值(D1,D2,D3).由于系统必须处于一个一致性,也就是这三个数据库的值要么同时更新成功,要么全部不更新.不然会造成子系统有些指令成功了,有些指令尚未执行.导致对结果理解混乱. 那么,MySQL如何实

随机推荐