首页 > 数据库 >SQL中进行转列的几种方式

SQL中进行转列的几种方式

时间:2022-10-14 12:41:22浏览次数:47  
标签:Insert courseno Into SQL 几种 转列 Values scores stuid


SQL中进行专列

SQL中进行转列

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

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

SQL中进行转列的几种方式_优化


SQL中进行转列的几种方式_sql_02


SQL中进行转列的几种方式_数据_03

数据准备

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);

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

SQL中进行转列的几种方式_优化_04

静态行转列

  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

SQL中进行转列的几种方式_SQL_05


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

SQL中进行转列的几种方式_SQL_06


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

SQL中进行转列的几种方式_sql_07


在这里解释一下 :

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;

SQL中进行转列的几种方式_sql_08


最终结果如下 :

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;

SQL中进行转列的几种方式_sql_09


这里简单说一下,先生命一个变量赋值为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 ;

SQL中进行转列的几种方式_SQL_10


标签:Insert,courseno,Into,SQL,几种,转列,Values,scores,stuid
From: https://blog.51cto.com/u_15829196/5756185

相关文章

  • aidlux 安装 mysql 并设置密码及远程访问
    本文链接:aidlux安装mysql并设置密码及远程访问-Tiac-博客园(cnblogs.com) 一、安装mysql直接在应用中心里搜索安装mysql即可 二、启动mysql终端输入......
  • SQL Server 2016 安装
    数据库安装选择全新安装模式继续安装输入产品秘钥:这里使用演示秘钥进行接受许可规则检测可以后期再开放防火墙对外端口选择需要安装的功能,想省事可以选择【全选......
  • 一款DBA开发的Oracle迁移MySQL工具-oracle_mig_mysql
    这是一款由业余DBA写的数据迁移工具,可在线一键迁移Oracle数据库到MySQL数据库,包含表元数据、数据行迁移、视图、部分触发器、自增列、索引约束等对象自动创建。操作简单,开......
  • MySQL事务隔离
    MySQL事务隔离该文摘抄自林晓斌老师的文章提到事务,你肯定不陌生,和数据库打交道的时候,我们总是会用到事务。最经典的例子就是转账,你要给朋友小王转100块钱,而此时你的银......
  • 模拟高并发测试的几种方式
    Postman下载软件包#官网启动测试案例创建一个Collections,将接口保存进Collections点击Runner,选择需要并发测试的接口设置相关参数,点击Run。ApacheBench下载软件包#官网ht......
  • linux 安装mysql8.0.11
    1.使用系统的root账户2.切换到/use/local目录下3.下载mysql?wgethttps://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.21-linux-glibc2.12-x86_64.tar.xz也可以......
  • MySql时间处理函数的学习与实践
    前言日常业务开发中,我们经常需要跟SQl的日期打交道,比如查询最近30天的订单,查询某一个月的订单量,统计某天每小时的下单量等等,于是整理了以下MySql时间处理函数。DATE_ADD()定......
  • MySQL日志15连问
    前言大家好,我是田螺哥。金九银十已经来了,整理了15道经典MySQL日志面试题,希望对大家有帮助。1.redolog是什么?为什么需要redolog?redolog是什么呢?redolog是重做日......
  • MySQL 中的 “My” 是什么意思?
    前两天,我跟一个面试官聊天,发现一个普遍现象,不少候选人,对数据库的认知,还处在比较基础的阶段,以为会写“增删改查”、做表关联就足够了,那些工作中经常出现的问题,却支支吾吾答不......
  • 美团二面:Redis与MySQL双写一致性如何保证?
    前言四月份的时候,有位好朋友去美团面试。他说,被问到Redis与MySQL双写一致性如何保证?这道题其实就是在问缓存和数据库在双写场景下,一致性是如何保证的?本文将跟大家一起来探讨......