一文弄懂MYSQL如何列转行
作者:以后养只狗 时间:2024-01-17 18:05:21
一、需求:
有三张表,学生表、成绩表和课程表,我们可以通过连表查询出学生姓名、课程及对应的成绩: 所需表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();
这样每次直接调用就可以了?
来源:https://blog.csdn.net/qq_42145865/article/details/108186843
标签:mysql,列转行
0
投稿
猜你喜欢
MySQL数据库磁盘优化
2008-11-24 17:29:00
Golang编程实现删除字符串中出现次数最少字符的方法
2024-05-25 15:15:56
SQL Server中统计每个表行数的快速方法
2024-01-19 08:51:21
微信小程序 swiper 组件遇到的问题及解决方法
2024-04-18 09:40:47
不能忽略c#中的using和as操作符的用处
2024-03-23 08:08:41
Ubuntu16安装Python3.9的实现步骤
2021-01-23 14:04:53
用Python复现二战德军enigma密码机
2022-04-12 23:22:59
SQLServer2005 没有服务器名称的两种解决方法
2024-01-20 10:29:43
Go 语言结构体链表的基本操作
2024-02-07 18:51:11
编写Python脚本来实现最简单的FTP下载的教程
2022-11-12 01:25:45
python元组和字典的内建函数实例详解
2021-09-13 09:34:56
SQLServer中字符串左对齐或右对齐显示的sql语句
2012-06-06 19:36:45
python3读取图片并灰度化图片的四种方法(OpenCV、PIL.Image、TensorFlow方法)总结
2021-06-20 20:47:41
利用PHP自动生成印有用户信息的名片
2023-09-10 22:30:56
MySQL中通过EXPLAIN如何分析SQL的执行计划详解
2024-01-20 00:12:43
Python设计足球联赛赛程表程序的思路与简单实现示例
2023-05-02 20:58:05
python读取.data文件的实现
2021-10-28 06:24:05
简单文件操作python 修改文件指定行的方法
2022-07-13 15:02:52
Golang实现的聊天程序服务端和客户端代码分享
2024-05-09 14:54:58
python正则表达式re.match()匹配多个字符方法的实现
2023-07-30 08:25:16