前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SQL中进行转列的几种方式

SQL中进行转列的几种方式

作者头像
海仔
发布2019-08-06 11:05:07
2.8K0
发布2019-08-06 11:05:07
举报
文章被收录于专栏:海仔技术驿站海仔技术驿站

SQL中进行专列

  • SQL中进行转列
    • 以下是这次sql转换的表结构以及数据
  • 数据准备
  • 1、学生表
  • 2、课程表
  • 3、成绩表
  • 4、基本数据
  • 我们先看一下最基本的查询效果是什么样的
  • 静态行转列
  • 动态行转列
  • 动态的列是拿到了,那如何再结合SQL语句进行查询得到结果呢?
  • 存储过程--动态行转列

SQL中进行转列

在很多笔试的程序员中会有很多写SQL的情况,其中很多时候会考察行转列。那么这个时候如果能写出来几种行转列的SQL,会给面试官留下比较好的印象。

以下是这次sql转换的表结构以及数据

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

数据准备

1、学生表

代码语言:javascript
复制
	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、课程表

代码语言:javascript
复制
	CREATE TABLE `curriculum` (
	 `courseno` VARCHAR(20) NOT NULL,
	 `coursenm` VARCHAR(100) NOT NULL,
	 PRIMARY KEY (`courseno`)
	)
	COMMENT='课程表'
	COLLATE='utf8_general_ci'
	ENGINE=InnoDB;

3、成绩表

代码语言:javascript
复制
	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;

4、基本数据

代码语言:javascript
复制
	/*学生表数据*/
	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 curriculum (courseno, coursenm) Values('C001', '大学语文');
	Insert Into curriculum (courseno, coursenm) Values('C002', '新视野英语');
	Insert Into curriculum (courseno, coursenm) Values('C003', '离散数学');
	Insert Into curriculum (courseno, coursenm) Values('C004', '概率论与数理统计');
	Insert Into curriculum (courseno, coursenm) Values('C005', '线性代数');
	Insert Into curriculum (courseno, coursenm) Values('C006', '高等数学(一)');
	Insert Into curriculum (courseno, coursenm) Values('C007', '高等数学(二)');
	/*成绩表数据*/
	Insert Into number_result(stuid, courseno, scores) Values('1001', 'C001', 67);
	Insert Into number_result(stuid, courseno, scores) Values('1002', 'C001', 68);
	Insert Into number_result(stuid, courseno, scores) Values('1003', 'C001', 69);
	Insert Into number_result(stuid, courseno, scores) Values('1004', 'C001', 70);
	Insert Into number_result(stuid, courseno, scores) Values('1005', 'C001', 71);
	Insert Into number_result(stuid, courseno, scores) Values('1006', 'C001', 72);
	Insert Into number_result(stuid, courseno, scores) Values('1001', 'C002', 87);
	Insert Into number_result(stuid, courseno, scores) Values('1002', 'C002', 88);
	Insert Into number_result(stuid, courseno, scores) Values('1003', 'C002', 89);
	Insert Into number_result(stuid, courseno, scores) Values('1004', 'C002', 90);
	Insert Into number_result(stuid, courseno, scores) Values('1005', 'C002', 91);
	Insert Into number_result(stuid, courseno, scores) Values('1006', 'C002', 92);
	Insert Into number_result(stuid, courseno, scores) Values('1001', 'C003', 83);
	Insert Into number_result(stuid, courseno, scores) Values('1002', 'C003', 84);
	Insert Into number_result(stuid, courseno, scores) Values('1003', 'C003', 85);
	Insert Into number_result(stuid, courseno, scores) Values('1004', 'C003', 86);
	Insert Into number_result(stuid, courseno, scores) Values('1005', 'C003', 87);
	Insert Into number_result(stuid, courseno, scores) Values('1006', 'C003', 88);
	Insert Into number_result(stuid, courseno, scores) Values('1001', 'C004', 88);
	Insert Into number_result(stuid, courseno, scores) Values('1002', 'C004', 89);
	Insert Into number_result(stuid, courseno, scores) Values('1003', 'C004', 90);
	Insert Into number_result(stuid, courseno, scores) Values('1004', 'C004', 91);
	Insert Into number_result(stuid, courseno, scores) Values('1005', 'C004', 92);
	Insert Into number_result(stuid, courseno, scores) Values('1006', 'C004', 93);
	Insert Into number_result(stuid, courseno, scores) Values('1001', 'C005', 77);
	Insert Into number_result(stuid, courseno, scores) Values('1002', 'C005', 78);
	Insert Into number_result(stuid, courseno, scores) Values('1003', 'C005', 79);
	Insert Into number_result(stuid, courseno, scores) Values('1004', 'C005', 80);
	Insert Into number_result(stuid, courseno, scores) Values('1005', 'C005', 81);
	Insert Into number_result(stuid, courseno, scores) Values('1006', 'C005', 82);
	Insert Into number_result(stuid, courseno, scores) Values('1001', 'C006', 77);
	Insert Into number_result(stuid, courseno, scores) Values('1002', 'C006', 78);
	Insert Into number_result(stuid, courseno, scores) Values('1003', 'C006', 79);
	Insert Into number_result(stuid, courseno, scores) Values('1004', 'C006', 80);
	Insert Into number_result(stuid, courseno, scores) Values('1005', 'C006', 81);
	Insert Into number_result(stuid, courseno, scores) Values('1006', 'C006', 82);

我们先看一下最基本的查询效果是什么样的

在这里插入图片描述
在这里插入图片描述

静态行转列

代码语言:javascript
复制
	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 st
	Left Join number_result s On st.stuid = s.stuid
	Left Join curriculum c On c.courseno = s.courseno
	Group by st.stuid
在这里插入图片描述
在这里插入图片描述

很多人肯定不理解为什么要使用Max函数,实际上大家都知道聚合函数是和分组进行搭配使用的。这一点毋庸置疑,那么大家可以把Max函数去掉看看会显示什么效果。切记去掉Max函数记得把分组也去掉,这样才能看到本质。

在这里插入图片描述
在这里插入图片描述

这时大家会发现没列都出现了重复的数据,而且只有一列是有值得。其他列都是0.那么这个时候就应该能很清楚的认识到,为什么使用Max函数了。在分组的同时取一组中的最大值。 静态行转列有一个弊端就是第一确定有多少个课程,然后再把课程名称拿出来再写查询语句。但是这样会写很多东西。

动态行转列

首先我们要动态的获取是列的数据 : 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列 : SELECT GROUP_CONCAT( DISTINCT CONCAT( ‘MAX(IF(c.coursenm = ‘’’, c.coursenm, ‘’’, s.scores, 0)) AS ‘’’, c.coursenm, ‘’’’ ) ) FROM curriculum c;

在这里插入图片描述
在这里插入图片描述

在这里解释一下 : concat()函数 : 将多个字符串连接成一个字符串。 语法:concat_ws(separator, str1, str2, …) 说明:第一个参数指定分隔符。需要注意的是分隔符不能为null,如果为null,则返回结果为null。 group_concat()函数 :将group by产生的同一个分组中的值连接起来,返回一个字符串结果。 语法:group_concat( [distinct] 要连接的字段 [order by 排序字段 asc/desc ] [separator ‘分隔符’] )。 说明:通过使用distinct可以排除重复值;如果希望对结果中的值进行排序,可以使用order by子句;separator是一个字符串值,缺省为一个逗号。

动态的列是拿到了,那如何再结合SQL语句进行查询得到结果呢?

代码语言:javascript
复制
这里要说明一点,因为用到了拼接函数,如果像上面的查询语句,只是把那几行语句替换掉,也就是下面这样	
Select st.stuid, st.stunm, 
(
 SELECT
 GROUP_CONCAT(DISTINCT
 CONCAT(
 'MAX(IF(c.coursenm = ''',
 c.coursenm,
 ''', s.scores, NULL)) AS ',
 c.coursenm
 )
 )
 FROM curriculum c
)
From Student st
Left Join number_result s On st.stuid = s.stuid
Left Join curriculum c On c.courseno = s.courseno
Group by st.stuid;
在这里插入图片描述
在这里插入图片描述

最终结果如下 : SET @SQL = NULL; SELECT GROUP_CONCAT( DISTINCT CONCAT( ‘MAX(IF(c.coursenm = ‘’’, c.coursenm, ‘’’, s.scores, 0)) AS ‘’’, c.coursenm, ‘’’’ ) ) INTO @SQL FROM curriculum c; SET @SQL = CONCAT( 'Select st.stuid, st.stunm, ‘, @SQL, ’ From Student st Left Join number_result s On st.stuid = s.stuid Left Join curriculum c On c.courseno = s.courseno Group by st.stuid’ ); PREPARE stmt FROM @SQL; EXECUTE stmt; DEALLOCATE PREPARE stmt;

在这里插入图片描述
在这里插入图片描述

这里简单说一下,先生命一个变量赋值为null,把拼接的查询sql赋值给声明的变量表中,也可以理解为生成一个临时表,把查询出来的数据放到临时表中。预定义一个语句,并将它赋给 stmt。

存储过程–动态行转列

代码语言:javascript
复制
用存储过程的好处是,方便我们调用,相当于一个函数,其他可能也是类似的查询不需再重复写代码,直接调存储过程就好,还能随心所欲的加上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 @sql
FROM curriculum c;
 
SET @sql = CONCAT('Select st.stuid, st.stunm, ', @sql, 
 ' From student st 
 Left Join number_result s On st.stuid = s.stuid
 Left Join curriculum c On c.courseno = s.courseno');
 
IF stuid is not null and stuid <> '' then
SET @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 ;
在这里插入图片描述
在这里插入图片描述
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年05月04日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • SQL中进行专列
  • SQL中进行转列
    • 以下是这次sql转换的表结构以及数据
    • 数据准备
    • 1、学生表
    • 2、课程表
    • 3、成绩表
    • 4、基本数据
    • 我们先看一下最基本的查询效果是什么样的
    • 静态行转列
    • 动态行转列
    • 动态的列是拿到了,那如何再结合SQL语句进行查询得到结果呢?
    • 存储过程–动态行转列
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档