linq to sql 行转列_SQL中进行转列的几种方式

SQL中进行转列

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

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

c7d88dc04bacaaaeebc7008f39a75f72.png

34de39e946b120f0ff6fa26e9e871242.png

964219ba1b068bbfa7d7828bd0de0f52.png

数据准备

1、学生表
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、课程表
CREATE TABLE `curriculum` ( `courseno` VARCHAR(20) NOT NULL, `coursenm` VARCHAR(100) NOT NULL, PRIMARY KEY (`courseno`) ) COMMENT='课程表' COLLATE='utf8_general_ci' ENGINE=InnoDB;

3、成绩表
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、基本数据
/*学生表数据*/ 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);

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

56e597c593985719705ee7f76021008f.png

静态行转列
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

9f5874b22213989dd6924d1366b72f58.png


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

e4eb3ddaf1d72c639e83a1f06365e215.png


这时大家会发现没列都出现了重复的数据,而且只有一列是有值得。其他列都是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;

64f9c04389c317b2bca8ccf3b136d9fa.png


在这里解释一下 :
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语句进行查询得到结果呢?
这里要说明一点,因为用到了拼接函数,如果像上面的查询语句,只是把那几行语句替换掉,也就是下面这样 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;

2b3d610d3c08729d2122c68b1c13d896.png


最终结果如下 :
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;

867b4503f8929049eb8ee37028979b3a.png


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

存储过程–动态行转列
用存储过程的好处是,方便我们调用,相当于一个函数,其他可能也是类似的查询不需再重复写代码,直接调存储过程就好,还能随心所欲的加上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 ;

5a0384ab94db2464c2c1f3fb58b267b5.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值