MYSQL之如何列转行
一、需求:有三张表,学生表、成绩表和课程表,我们可以通过连表查询出学生姓名、课程及对应的成绩:
所需表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_scoreFROM student sLEFT JOIN score sc on sc.s_id=s.s_idLEFT 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_scoreFROM student sLEFT JOIN score sc on sc.s_id=s.s_idLEFT 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_scoreFROM student sLEFT JOIN score sc on sc.s_id=s.s_idLEFT 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;SELECTGROUP_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如何把列转行_mysql列转行的技巧(分享)
前言: 由于很多业务表因为历史原因或者性能原因,都使用了违反第一范式的设计模式.即同一个列中存储了多个属性值(具体结构见下表). 这种模式下,应用常常需要将这个列依据分隔符进行分割,并得到列转行的结果 ...
- sql server 怎么实现mysql中group_concat,列转行,列用分隔符拼接字符串
为什么80%的码农都做不了架构师?>>> create table tb(id int, value varchar(10)) insert into tb values(1, ...
- mysql collectset_005.hive列转行 (collect_set() 去重)
一.问题 hive如何将 a b 1 a b 2 a b 3 c d 4 c d ...
- MYSQL中的列转行
select id, group_concat(name) as NAME from student group by id; id name 1 张三 2 李四 1 王 ...
- MYSQL 列转行方法
MYSQL 列转行方法 目标 上周遇到个业务场景,要求把一列中用分隔符连接的数据,通过分隔符转多行,形如: 转为 准备 表结构 CREATE TABLE `t_tag` (`id` int NOT N ...
- mysql 列转行union all_MySQL中的列转行 - osc_qheq8wav的个人空间 - OSCHINA - 中文开源技术交流社区...
mysql中的列转行 在工作中遇到的一个MySQL列转行的统计: 场景 用户访问app时会跳出标签选择页面让用户选择喜欢的标签,在数据库中记录的是数组样式的字符串,数据样式大致如下: id user_ ...
- mysql行转列和列转行_mysql 行转列和列转行实例详解
mysql行转列.列转行 语句不难,不做多余解释了,看语句时,从内往外一句一句剖析 行转列 有如图所示的表,现在希望查询的结果将行转成列 建表语句如下: create table `test_tb_g ...
- mysql 分组 列转行,mysql 列转行以及岁月分组
SELECT count(DISTINCT(a.rect_id)) zcount, a.job_dept, DATE_FORMAT(submit_date, '%Y-%m') zsubmit_date ...
- mysql 列合并_mysql 列转行,合并字段的方法(必看)
数据表: 列转行:利用max(case when then) max---聚合函数 取最大值 (case course when '语文' then score else 0 end) ---判断 a ...
最新文章
- python lambda ,map详解
- 0037 Java学习笔记-多线程-同步代码块、同步方法、同步锁
- 在SharePoint 2010中创建网站的权限级别
- ★Linux磁盘配额的使用 ★——牛刀小试
- mediarecorder添加时间戳_Python脚本实现数据处理(官方实例)和Hive自带时间函数...
- PHP课程第一次实验作业提交
- 数据库异常---ORA-01436: 用户数据中的 CONNECT BY loop in user data 循环
- 医学计算机语言s,B/S框架医学图像处理系统的算法接入方法研究
- serialVersionUID 生成
- 谷歌搜索没有相机图标_关于Google图片网站不能以图搜图的解决方案
- Epicor系统二次开发
- RHEL6: Server panicked in 'redirfs' module
- 双目视觉定位方案设计
- Android加载网络图片学习过程
- Java面试题 Web+EJB Spring+数据结构 算法计算机基础
- Google drive下载失败,网络错误
- 一口气笑穿极简印度史,简到崩溃,笑到流泪(二)
- retrofit设置单个请求的超时
- (Golang)外观模式 VS 工厂模式
- 手游无限级服务器,吃鸡无限服务器忙碌 | 手游网游页游攻略大全