经典SQL问题: 行转列,列转行
情景简介
学校里面记录成绩,每个人的选课不一样,而且以后会添加课程,所以不需要把所有课程当作列。数据库grade里面数据如下图,假定每个人姓名都不一样,作为主键。本文以MySQL为基础,其他数据库会有些许语法不同。
数据库数据:
mysql> select * from grade;
+------+--------+--------+-------+
| id | name | course | score |
+------+--------+--------+-------+
| 1 | 张三 | 语文 | 80 |
| 2 | 张三 | 数学 | 90 |
| 3 | 张三 | 英语 | 90 |
| 4 | 李四 | 语文 | 47 |
| 5 | 李四 | 数学 | 78 |
| 6 | 王五 | 数学 | 97 |
+------+--------+--------+-------+
6 rows in set (0.00 sec) mysql>
处理后效果:
+--------+--------+--------+--------+
| name | 语文 | 数学 | 英语 |
+--------+--------+--------+--------+
| 张三 | 80 | 90 | 90 |
| 李四 | 47 | 78 | NULL |
| 王五 | NULL | 97 | NULL |
+--------+--------+--------+--------+
3 rows in set (0.00 sec) mysql>
下面介绍三种方法:
方法一:
SELECT DISTINCT a.name,
(SELECT score FROM grade b WHERE a.name=b.name AND b.course='语文' ) AS '语文',
(SELECT score FROM grade b WHERE a.name=b.name AND b.course='数学' ) AS '数学',
(SELECT score FROM grade b WHERE a.name=b.name AND b.course='英语' ) AS '英语'
FROM grade a
方法二:
SELECT name,
SUM(CASE course WHEN '语文' THEN score END ) AS '语文',
SUM(CASE course WHEN '数学' THEN score END ) AS '数学',
SUM(CASE course WHEN '英语' THEN score END ) AS '英语'
FROM grade GROUP BY name
方法三:
DELIMITER &&
CREATE PROCEDURE sp_count()
BEGIN
#课程名称
DECLARE course_n VARCHAR(20);
#所有课程数量
DECLARE count INT;
#计数器
DECLARE i INT DEFAULT 0;
#拼接SQL字符串
SET @s = 'SELECT name';
SET count = (SELECT COUNT(distinct course) FROM grade);
WHILE i < count DO
SET course_n = (SELECT course FROM grade LIMIT i,1);
SET @s = CONCAT(@s, ', SUM(CASE course WHEN ','\'', course_n,'\'',' THEN score END )',' AS ','\'',course_n,'\'');
SET i = i+1;
END WHILE;
SET @s = CONCAT(@s, ' FROM grade GROUP BY name');
#用于调试
#SELECT @s;
PREPARE stmt FROM @s;
EXECUTE stmt;
END
&& call sp_count();
方法分析:
第一种方法使用了表连接。
第二种使用了分组,对每个分组分别处理。
第三种使用了存储过程,其实是第二种方法的动态化,先计算出所有课程的数量,然后对每个分组进行课程查询。
很明显前两种方法属于硬编码,增加课程后就需要修改SQL。而第三种则没有这种问题。
Note:
MySQL中不能在一个存储过程中删除另一个存储过程,只能调用另一个存储过程
本来想在方法三里面写上:DROP PROCEDURE IF EXISTS sp_count();这是错误的。调试的时候如果写错了,只能手动删除了,也没找到好方法。
结果转出行或者一个拼接字符串:《mysql函数之五:group_concat mysql 把结果集中的一列数据用指定分隔符转换成一行》
二、列转行
原来是这样
名称 单价 进货价
内存 120 100 现在想这样
名称 价格
内存 120
内存 100
mysql> select * from device_info;
+--------+--------+-----------+
| dname | danjia | jinhuojia |
+--------+--------+-----------+
| 内存 | 100 | 80 |
| CPU | 200 | 150 |
| 硬盘 | 300 | 230 |
+--------+--------+-----------+
3 rows in set (0.00 sec) mysql>
sql:
mysql> SELECT * FROM
-> (SELECT dname, danjia AS jiage FROM device_info
-> UNION ALL
-> SELECT dname,jinhuojia AS jiage FROM device_info) AS temp
-> ORDER BY dname;
+--------+-------+
| dname | jiage |
+--------+-------+
| CPU | 150 |
| CPU | 200 |
| 内存 | 80 |
| 内存 | 100 |
| 硬盘 | 230 |
| 硬盘 | 300 |
+--------+-------+
6 rows in set (0.03 sec) mysql>
经典SQL问题: 行转列,列转行的更多相关文章
- sql 多行转多列,多行转一列合并数据,列转行
下面又是一种详解:
- SQL多行转多列
--★转换结果如上图 1.首先创建表: CREATE TABLE [成绩表]( ,) NOT NULL, )NULL, , )NULL, , )NULL, , )NULL ) ON [PRIMARY] ...
- 【收藏】SQL多行变一列
CREATE TABLE DEPT (DeptNo INT IDENTITY(1, 1)NOT NULL , Country VARCHAR(50) , Location VARCHAR(50) ...
- SQL多行变一列
CREATE TABLE DEPT (DeptNo INT IDENTITY(1, 1)NOT NULL , Country VARCHAR(50) , Location VARCHAR(50) ...
- sql多行合并一列
with a as( select * from( select 1 userId , '天津' province union select 1 userId , '北京' union select ...
- SQL Server 行转列,列转行。多行转成一列
一.多行转成一列(并以","隔开) 表名:A 表数据: 想要的查询结果: 查询语句: SELECT name , value = ( STUFF(( SELECT ',' + va ...
- sql的行转列(PIVOT)与列转行(UNPIVOT) webapi 跨域问题 Dapper 链式查询 扩展 T4 代码生成 Demo (抽奖程序)
sql的行转列(PIVOT)与列转行(UNPIVOT) 在做数据统计的时候,行转列,列转行是经常碰到的问题.case when方式太麻烦了,而且可扩展性不强,可以使用 PIVOT,UNPIVOT比 ...
- SQL Server 行转列,列转行
一.多行转成一列(并以","隔开) 表名:A 表数据: 想要的查询结果: 查询语句: SELECT name , value = ( STUFF(( SELECT ',' + va ...
- Sql server 中将数据行转列列转行(二)
老规矩,先弄一波测试数据,数据填充代码没有什么意义,先折叠起来: /* 第一步:创建临时表结构 */ CREATE TABLE #Student --创建临时表 ( StuName ), --学生名称 ...
- 在mybatis中使用存储过程报错java.sql.SQLException: ORA-06550: 第 1 行, 第 7 列: PLS-00905: 对象 USER1.HELLO_TEST 无效 ORA-06550: 第 1 行, 第 7 列:
hello_test是我的存储过程的名字,在mapper.xml文件中是这么写的 <select id="getPageByProcedure" statementType= ...
随机推荐
- 【转载】丑数humble numbers
转载地址:http://blog.csdn.net/qwerty_xk/article/details/12749961 题:只有2 3 5 这三个因子的数,求第1500个 设1为第一个丑数,求第 ...
- freemarker入门实例与源码研究准备工作
首先去freemarker官网下载源码jar包,本文是基于freemarker-2.3.21.tar.gz进行研究的.解压源码包,找到freemarker的源码部分导入eclipse工程中.需要注意的 ...
- Apache Phoenix的Array类型
Apache Phoenix支持JDBC ARRAY类型,任何原生的数据类型就可以在ARRAY中使用.下面我介绍一下在创建的表中使用ARRAY类型. 先看一下创建表的SQL语句: CREATE TAB ...
- HDU 4000 Fruit Ninja (树状数组+反向思维)
题意:给你一串数且每个数都不同,问你(x,y,z)出现 x<z<y 的总次数 首先我们直接想的话不能使用O(n*log2 n)解决,所以可以正难则反 可以求得x<(y,z)的值,减去 ...
- Intel Code Challenge Elimination Round (Div.1 + Div.2, combined) C. Destroying Array
C. Destroying Array time limit per test 1 second memory limit per test 256 megabytes input standard ...
- 【转】java中静态方法和非静态方法的存储
将某 class 产生出一个 instance 之后,此 class 所有的 instance field 都会新增一份,那么所有的 instance method 是否也会新增一份?答案是不会,我们 ...
- 使用 ActiveMQ 创建 Java 应用
本章重点 Java 应用中内嵌 ActiveMQ 使用 Spring 内嵌 ActiveMQ 创建请求/响应应用 使用 Spring 构建 JMS 客户端
- 51nod 1672 贪心/队列
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1672 1672 区间交 基准时间限制:1 秒 空间限制:131072 K ...
- Linq练习题
1 . 查询 Student 表中的所有记录的 Sname . Ssex 和 Class 列. select sname,ssex,class from student Linq: from ...
- python--pycharm汉化
一.准备工具 1.pycharm软件 2.汉化包 二.解压汉化包 三.将resources_cn.jar复制到pycharm文件中lib目录下 四.重新打开pycharm