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

所需表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之如何列转行相关推荐

  1. mysql如何把列转行_mysql列转行的技巧(分享)

    前言: 由于很多业务表因为历史原因或者性能原因,都使用了违反第一范式的设计模式.即同一个列中存储了多个属性值(具体结构见下表). 这种模式下,应用常常需要将这个列依据分隔符进行分割,并得到列转行的结果 ...

  2. sql server 怎么实现mysql中group_concat,列转行,列用分隔符拼接字符串

    为什么80%的码农都做不了架构师?>>>    create table tb(id int, value varchar(10)) insert into tb values(1, ...

  3. mysql collectset_005.hive列转行 (collect_set() 去重)

    一.问题 hive如何将 a       b       1 a       b       2 a       b       3 c       d       4 c       d       ...

  4. MYSQL中的列转行

    select id, group_concat(name) as NAME from student group by id; id    name 1     张三 2     李四 1     王 ...

  5. MYSQL 列转行方法

    MYSQL 列转行方法 目标 上周遇到个业务场景,要求把一列中用分隔符连接的数据,通过分隔符转多行,形如: 转为 准备 表结构 CREATE TABLE `t_tag` (`id` int NOT N ...

  6. mysql 列转行union all_MySQL中的列转行 - osc_qheq8wav的个人空间 - OSCHINA - 中文开源技术交流社区...

    mysql中的列转行 在工作中遇到的一个MySQL列转行的统计: 场景 用户访问app时会跳出标签选择页面让用户选择喜欢的标签,在数据库中记录的是数组样式的字符串,数据样式大致如下: id user_ ...

  7. mysql行转列和列转行_mysql 行转列和列转行实例详解

    mysql行转列.列转行 语句不难,不做多余解释了,看语句时,从内往外一句一句剖析 行转列 有如图所示的表,现在希望查询的结果将行转成列 建表语句如下: create table `test_tb_g ...

  8. mysql 分组 列转行,mysql 列转行以及岁月分组

    SELECT count(DISTINCT(a.rect_id)) zcount, a.job_dept, DATE_FORMAT(submit_date, '%Y-%m') zsubmit_date ...

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

    数据表: 列转行:利用max(case when then) max---聚合函数 取最大值 (case course when '语文' then score else 0 end) ---判断 a ...

最新文章

  1. python lambda ,map详解
  2. 0037 Java学习笔记-多线程-同步代码块、同步方法、同步锁
  3. 在SharePoint 2010中创建网站的权限级别
  4. ★Linux磁盘配额的使用 ★——牛刀小试
  5. mediarecorder添加时间戳_Python脚本实现数据处理(官方实例)和Hive自带时间函数...
  6. PHP课程第一次实验作业提交
  7. 数据库异常---ORA-01436: 用户数据中的 CONNECT BY loop in user data 循环
  8. 医学计算机语言s,B/S框架医学图像处理系统的算法接入方法研究
  9. serialVersionUID 生成
  10. 谷歌搜索没有相机图标_关于Google图片网站不能以图搜图的解决方案
  11. Epicor系统二次开发
  12. RHEL6: Server panicked in 'redirfs' module
  13. 双目视觉定位方案设计
  14. Android加载网络图片学习过程
  15. Java面试题 Web+EJB Spring+数据结构 算法计算机基础
  16. Google drive下载失败,网络错误
  17. 一口气笑穿极简印度史,简到崩溃,笑到流泪(二)
  18. retrofit设置单个请求的超时
  19. (Golang)外观模式 VS 工厂模式
  20. 手游无限级服务器,吃鸡无限服务器忙碌 | 手游网游页游攻略大全

热门文章

  1. 【Python】用Python制作一个名片管理系统
  2. PC - Chrome 浏览器如何开启无痕模式?
  3. android判断两个图片相同,android中比较两张图片的相似度
  4. idea修改代码提示的快捷键
  5. 加班的程序员:996 没有未来
  6. SAXReader 读文件读不出来
  7. 这个vue3的应用框架你学习了吗?
  8. HTML自学笔记-1(进入篇)
  9. Android开发入门到实战精通 完整全套开发教程送给你
  10. Linux双硬盘引导,Linux系统下双硬盘多系统引导深入探究