一、行转列

1、建表

CREATE TABLE score(
student_id VARCHAR(20) NOT NULL COMMENT '学生编号' DEFAULT '',
student_name VARCHAR(50) NOT NULL COMMENT '学生姓名' DEFAULT '',
gender VARCHAR(10) NOT NULL COMMENT '学生性别' DEFAULT '',
subject_name VARCHAR(50) NOT NULL COMMENT '课程名称' DEFAULT '',
score INTEGER NOT NULL COMMENT '分数' DEFAULT 0
)ENGINE=MyISAM DEFAULT CHARSET=gbk COMMENT='学生成绩'; DELETE FROM score; INSERT INTO score VALUES('S001','张三','男','高等数学',82);
INSERT INTO score VALUES('S001','张三','男','计算机导论',67);
INSERT INTO score VALUES('S001','张三','男','概率论',90);
INSERT INTO score VALUES('S001','张三','男','机械原理',82);
INSERT INTO score VALUES('S002','李四','男','高等数学',78);
INSERT INTO score VALUES('S002','李四','男','计算机导论',76);
INSERT INTO score VALUES('S002','李四','男','概率论',65);
INSERT INTO score VALUES('S002','李四','男','几何学',43);
INSERT INTO score VALUES('S003','王五','女','计算机导论',88);
INSERT INTO score VALUES('S003','王五','女','概率论',98);
INSERT INTO score VALUES('S003','王五','女','几何学',85);
INSERT INTO score VALUES('S004','赵六','男','高等数学',84);
INSERT INTO score VALUES('S004','赵六','男','计算机导论',76);
INSERT INTO score VALUES('S004','赵六','男','机械原理',65);
INSERT INTO score VALUES('S004','赵六','男','几何学',48);
INSERT INTO score VALUES('S005','孙七','女','高等数学',34);
INSERT INTO score VALUES('S005','孙七','女','计算机导论',91);
INSERT INTO score VALUES('S005','孙七','女','概率论',82);
INSERT INTO score VALUES('S005','孙七','女','机械原理',56);
INSERT INTO score VALUES('S005','孙七','女','几何学',70);

2、利用max(CASE ... WHEN ... THEN .. ELSE END) AS ""的方式来实现

##利用max(CASE ... WHEN ... THEN .. ELSE END) AS 的方式来实现
##判断如果是这门学科,就取它的成绩,否则赋值为0,然后在成绩与0里取最大值 SELECT
student_id,
student_name,
MAX(CASE WHEN subject_name = '高等数学' THEN score ELSE 0 END) AS '高等数学',
MAX(CASE WHEN subject_name = '计算机导论' THEN score ELSE 0 END) AS '计算机导论',
MAX(CASE WHEN subject_name = '概率论' THEN score ELSE 0 END) AS '概率论',
MAX(CASE WHEN subject_name = '机械原理' THEN score ELSE 0 END) AS '机械原理',
MAX(CASE WHEN subject_name = '几何学' THEN score ELSE 0 END) AS '几何学' FROM score
GROUP BY
student_id,
student_name
ORDER BY
student_id,
student_name;

3、求男女生各科平均成绩

##平均成绩肯定是总分除以人数,但是呢,有的学生没有某一门学科的成绩,我们把它变成0,
##变成0其实是不妥当的,因为变成0,在做除法的时候,也会算成一个人,这样除的结果就会不准确
##所以应该把0变成null SELECT
gender,
AVG(CASE WHEN subject_name = '高等数学' THEN score ELSE NULL END) AS '高等数学',
AVG(CASE WHEN subject_name = '计算机导论' THEN score ELSE NULL END) AS '计算机导论',
AVG(CASE WHEN subject_name = '概率论' THEN score ELSE NULL END) AS '概率论',
AVG(CASE WHEN subject_name = '机械原理' THEN score ELSE NULL END) AS '机械原理',
AVG(CASE WHEN subject_name = '几何学' THEN score ELSE NULL END) AS '几何学'
FROM score
GROUP BY
gender
ORDER BY
gender; 总结:
行转列,分组(GROUP BY)的列必须是除需要行转列之外的业务主键。
例如tb表中业务主键应该是cname和cource,但是cource需要进行行转列,所以需要按照cname分组。

4、子查询的方式,求男女生各科成绩平均值

##

SELECT
gender,
MAX(CASE WHEN subject_name = '高等数学' THEN score_avg ELSE 0 END) AS '高等数学',
MAX(CASE WHEN subject_name = '计算机导论' THEN score_avg ELSE 0 END) AS '计算机导论',
MAX(CASE WHEN subject_name = '概率论' THEN score_avg ELSE 0 END) AS '概率论',
MAX(CASE WHEN subject_name = '机械原理' THEN score_avg ELSE 0 END) AS '机械原理',
MAX(CASE WHEN subject_name = '几何学' THEN score_avg ELSE 0 END) AS '几何学'
FROM
(
SELECT
gender,
subject_name,
AVG(score) AS score_avg
FROM score
GROUP BY gender,subject_name
)a
GROUP BY gender
ORDER BY gender;

5、GROUP_CONCAT

GROUP_CONCAT():该函数返回带有来自一个分组的连接的非NULL值的字符串结果。

SELECT
student_id,
student_name,
GROUP_CONCAT(subject_name) AS 课程名称, GROUP_CONCAT(score) AS 分数
FROM score
GROUP BY
student_id,
student_name;

结果:

二、列转行

1、建表

###
employee_sales表: CREATE TABLE employee_sales(
employee_id VARCHAR(20) NOT NULL COMMENT '员工编号' DEFAULT '',
employee_name VARCHAR(50) NOT NULL COMMENT '员工姓名' DEFAULT '',
sales_amount_q1 DECIMAL(18,2) NOT NULL COMMENT '一季度销售金额' DEFAULT 0,
sales_amount_q2 DECIMAL(18,2) NOT NULL COMMENT '二季度销售金额' DEFAULT 0,
sales_amount_q3 DECIMAL(18,2) NOT NULL COMMENT '三季度销售金额' DEFAULT 0,
sales_amount_q4 DECIMAL(18,2) NOT NULL COMMENT '四季度销售金额' DEFAULT 0
)ENGINE=MyISAM DEFAULT CHARSET=gbk COMMENT='员工销售表'; INSERT INTO employee_sales VALUES('S001','张三',273193.41,84149.96,711798.18,847930.56);
INSERT INTO employee_sales VALUES('S002','李四',861586.57,819398.89,496788.47,1060.11);
INSERT INTO employee_sales VALUES('S003','王五',943899.97,793446.45,351139,640459.72);
INSERT INTO employee_sales VALUES('S004','赵六',585158.08,493034.64,576246.61,188906.14); ###
employee_assessment表: CREATE TABLE employee_assessment(
employee_id VARCHAR(20) NOT NULL COMMENT '员工编号' DEFAULT '',
employee_name VARCHAR(50) NOT NULL COMMENT '员工姓名' DEFAULT '',
assessment_level CHAR(4) NOT NULL COMMENT '季度考核等级' DEFAULT '',
sales_amount VARCHAR(500) NOT NULL COMMENT '销售金额' DEFAULT ''
)ENGINE=MyISAM DEFAULT CHARSET=gbk COMMENT='员工考核表'; INSERT INTO employee_assessment VALUES('S001','张三','AABC','273193.41,84149.96,711798.18,847930.56');
INSERT INTO employee_assessment VALUES('S002','李四','CBAB','861586.57,819398.89,496788.47,1060.11');
INSERT INTO employee_assessment VALUES('S003','王五','BBAC','943899.97,793446.45,351139,640459.72');
INSERT INTO employee_assessment VALUES('S004','赵六','BACA','585158.08,493034.64,576246.61,188906.14');

2、UNION ALL 列转行

##union all 合并多个子集
##加了一个季度字段,方便查看
select employee_id,employee_name,'一季度' as 季度,sales_amount_q1 from employee_sales
union all
select employee_id,employee_name,'二季度' as 季度,sales_amount_q2 from employee_sales
UNION ALL
SELECT employee_id,employee_name,'三季度' as 季度,sales_amount_q3 from employee_sales
UNION ALL
select employee_id,employee_name,'四季度' as 季度,sales_amount_q4 from employee_sales
ORDER BY employee_id;

3、列转行2

##
先看employee_assessment表数据:
+-------------+---------------+------------------+-----------------------------------------+
| employee_id | employee_name | assessment_level | sales_amount |
+-------------+---------------+------------------+-----------------------------------------+
| S001 | 张三 | AABC | 273193.41,84149.96,711798.18,847930.56 |
| S002 | 李四 | CBAB | 861586.57,819398.89,496788.47,1060.11 |
| S003 | 王五 | BBAC | 943899.97,793446.45,351139,640459.72 |
| S004 | 赵六 | BACA | 585158.08,493034.64,576246.61,188906.14 |
+-------------+---------------+------------------+-----------------------------------------+ ##
用union all列转行:
select employee_id,employee_name,assessment_level,'1' as 季度,right(left(assessment_level,1),1) from employee_assessment union all
select employee_id,employee_name,assessment_level,'2' as 季度,right(left(assessment_level,2),1) from employee_assessment union all
select employee_id,employee_name,assessment_level,'3' as 季度,right(left(assessment_level,3),1) from employee_assessment union all
select employee_id,employee_name,assessment_level,'4' as 季度,right(left(assessment_level,4),1) from employee_assessment; 结果:
+-------------+---------------+------------------+--------+-----------------------------------+
| employee_id | employee_name | assessment_level | 季度 | right(left(assessment_level,1),1) |
+-------------+---------------+------------------+--------+-----------------------------------+
| S001 | 张三 | AABC | 1 | A |
| S002 | 李四 | CBAB | 1 | C |
| S003 | 王五 | BBAC | 1 | B |
| S004 | 赵六 | BACA | 1 | B |
| S001 | 张三 | AABC | 2 | A |
| S002 | 李四 | CBAB | 2 | B |
| S003 | 王五 | BBAC | 2 | B |
| S004 | 赵六 | BACA | 2 | A |
| S001 | 张三 | AABC | 3 | B |
| S002 | 李四 | CBAB | 3 | A |
| S003 | 王五 | BBAC | 3 | A |
| S004 | 赵六 | BACA | 3 | C |
| S001 | 张三 | AABC | 4 | C |
| S002 | 李四 | CBAB | 4 | B |
| S003 | 王五 | BBAC | 4 | C |
| S004 | 赵六 | BACA | 4 | A |
+-------------+---------------+------------------+--------+-----------------------------------+ 上面用union all虽然可以得到结果,但是当数据多的时候,就要写很多行union all,不太好?

可以用两个表的笛卡尔积:

##
建sequence 表:
此表中的数据要和要拆分的字段数相同: CREATE TABLE sequence (seq_num INT); INSERT INTO sequence
VALUES
(1),
(2),
(3),
(4); ##
right和left函数组合使用,获取某一位字符:
加where条件是因为,现在assessment_level字段正好和sequence表中的字段数相等,但是当两个字段数不等时,比如assessment_level只有三个,
加上where就可以起过滤作用,如:length(assessment_level) = 3,3已经不>=seq_num了,就算seq_num中有4,也不会select出来;

select employee_id,employee_name,assessment_level,seq_num as 季度,right(left(assessment_level,seq_num),1)
from employee_assessment,sequence where length(assessment_level) >= seq_num; 结果:
+-------------+---------------+------------------+--------+-----------------------------------------+
| employee_id | employee_name | assessment_level | 季度 | right(left(assessment_level,seq_num),1) |
+-------------+---------------+------------------+--------+-----------------------------------------+
| S001 | 张三 | AABC | 1 | A |
| S001 | 张三 | AABC | 2 | A |
| S001 | 张三 | AABC | 3 | B |
| S001 | 张三 | AABC | 4 | C |
| S002 | 李四 | CBAB | 1 | C |
| S002 | 李四 | CBAB | 2 | B |
| S002 | 李四 | CBAB | 3 | A |
| S002 | 李四 | CBAB | 4 | B |
| S003 | 王五 | BBAC | 1 | B |
| S003 | 王五 | BBAC | 2 | B |
| S003 | 王五 | BBAC | 3 | A |
| S003 | 王五 | BBAC | 4 | C |
| S004 | 赵六 | BACA | 1 | B |
| S004 | 赵六 | BACA | 2 | A |
| S004 | 赵六 | BACA | 3 | C |
| S004 | 赵六 | BACA | 4 | A |
+-------------+---------------+------------------+--------+-----------------------------------------+ 上面已经很简便的得到结果了,其实mysql还有一个函数:substring函数,能实现right和left相同的功能; ##substring函数,结果应该和上面一样
select employee_id,employee_name,assessment_level,seq_num as 季度,substring(assessment_level,seq_num,1)
from employee_assessment,sequence where length(assessment_level) >= seq_num;

上面其实只是处理了assessment_level字段,sales_amount 字段还没有处理,值是以逗号分隔的 :

##mysql有这样一个函数:substring_index函数
##substring_index有三个参数:第一个是:要分隔的字段,第二个是:以什么分隔,第三个是:要取第几个逗号前面的数据
##还嵌套了一层substring_index,-1:从右边往前取一个,以逗号分隔
##这里的where,是先计算出逗号的个数,然后加1,在去和sequence表中的数据比较 select employee_id,employee_name,assessment_level,seq_num,sales_amount,substring_index(substring_index(sales_amount,',',seq_num),',',-1)
from employee_assessment,sequence
WHERE LENGTH(sales_amount) - LENGTH(REPLACE(sales_amount,',',''))+1 >= seq_num
ORDER BY employee_id;

SQL进阶-行转列&列转行的更多相关文章

  1. sql 多行转多列,多行转一列合并数据,列转行

    下面又是一种详解:

  2. SQL多行转多列

    --★转换结果如上图 1.首先创建表: CREATE TABLE [成绩表]( ,) NOT NULL, )NULL, , )NULL, , )NULL, , )NULL ) ON [PRIMARY] ...

  3. 【收藏】SQL多行变一列

    CREATE TABLE DEPT (DeptNo INT IDENTITY(1, 1)NOT NULL ,  Country VARCHAR(50) ,  Location VARCHAR(50) ...

  4. SQL多行变一列

    CREATE TABLE DEPT (DeptNo INT IDENTITY(1, 1)NOT NULL ,  Country VARCHAR(50) ,  Location VARCHAR(50) ...

  5. sql多行合并一列

    with a as( select * from( select 1 userId , '天津' province union select 1 userId , '北京' union select ...

  6. SQL Server 行转列,列转行。多行转成一列

    一.多行转成一列(并以","隔开) 表名:A 表数据: 想要的查询结果: 查询语句: SELECT name , value = ( STUFF(( SELECT ',' + va ...

  7. sql的行转列(PIVOT)与列转行(UNPIVOT) webapi 跨域问题 Dapper 链式查询 扩展 T4 代码生成 Demo (抽奖程序)

    sql的行转列(PIVOT)与列转行(UNPIVOT)   在做数据统计的时候,行转列,列转行是经常碰到的问题.case when方式太麻烦了,而且可扩展性不强,可以使用 PIVOT,UNPIVOT比 ...

  8. SQL Server 行转列,列转行

    一.多行转成一列(并以","隔开) 表名:A 表数据: 想要的查询结果: 查询语句: SELECT name , value = ( STUFF(( SELECT ',' + va ...

  9. Sql server 中将数据行转列列转行(二)

    老规矩,先弄一波测试数据,数据填充代码没有什么意义,先折叠起来: /* 第一步:创建临时表结构 */ CREATE TABLE #Student --创建临时表 ( StuName ), --学生名称 ...

随机推荐

  1. ER图VISIO 引入Mysql 反向工程

    1. 先到MySQL官方站点下载 MySQL Connector/ODBC 5.1并安装.下载地址为http://dev.mysql.com/downloads/connector/odbc/5.1. ...

  2. 总结:WPF中ResourceDictionary资源文件的查找和遍历方法

    原文:总结:WPF中ResourceDictionary资源文件的查找和遍历方法 一.查找包含制定关键字的资源 ResourceDictionary GetThemeDictionary()     ...

  3. JavaScript---正则使用,日期Date的使用,Math的使用,JS面向对象(工厂模式,元模型创建对象,Object添加方法)

    JavaScript---正则使用,日期Date的使用,Math的使用,JS面向对象(工厂模式,元模型创建对象,Object添加方法) 一丶正则的用法 创建正则对象: 方式一: var reg=new ...

  4. mockjs的基本使用入门

    相信很多前端同学都有一个困扰,就是没有后端数据的情况下感觉很多想法都不能动手去实现,这里介绍一个模拟后端数据的工具,可以一定程度上解决我们的困扰. 很多人或多或少的都听说过mockjs,都知道是一个模 ...

  5. Spring+SpringMVC+Hibernate 与 shiro 整合步骤

    目录 1. 业务需求分析 2. 创建数据库 3. 创建 maven webapp 工程 4. 创建实体类(POJO) 5. 配置 Hibernate 和 Mapping 5.1 Hibernate 主 ...

  6. Python xlrd模块读取Excel表中的数据

    1.xlrd库的安装 直接使用pip工具进行安装(当然也可以使用pycharmIDE进行安装,这里就不详述了) pip install xlrd 2.xlrd模块的一些常用命令 ①打开excel文件并 ...

  7. httprunner学习16-locust性能测试

    前言 HttpRunner 的 yaml 脚本文件,可以结合locust做性能测试 locust环境准备 安装完成 HttpRunner 后,系统中会新增locusts命令,但不会同时安装 Locus ...

  8. httprunner学习7-extract提取content返回对象

    前言 提取response返回的对象数据,用extract关键字.前面有关于token的取值,通过content.token取值. 本篇详细讲解如何从返回的json数据提取出想要的各种数据 conte ...

  9. Spring Boot 缓存 知识点

    每次调用需要缓存功能的方法时,Spring会检查指定参数的指定的目标方法是否已经被调用过:如果有就直接从缓存中获取方法调用后的结果,如果没有就调用方法并缓存结果后返回给用户.下次调用直接从缓存中获取. ...

  10. git 学习笔记 —— 保留/丢弃当前分支修改并切换至其他分支

    笔者在本地终端进行 git 工作目录的相关处理时,遇到由于某种情况需要使用 git checkout 命令切换到其他分支的情景.此时,若已经对当前分支做了一定的修改,则直接切换分支时 git 会提示错 ...