经典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= ...
随机推荐
- Android : 反射机制获取或设置系统属性(SystemProperties)【转】
本文转载自:https://blog.csdn.net/wei_lei/article/details/70312512 Android.os.SystemProperties 提供了获取和设置系统属 ...
- 简单的文件上传的下载(动态web项目)
1.在页面中定义一个form表单,如下: <!-- 文件上传 --> <form action="${pageContext.request.contextPath}/Fi ...
- Caused by: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'company' in 'class java.lang.String'
Caused by: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named ' ...
- JConsole操作手册
一篇Sun项目主页上介绍JConsole使用的文章,前段时间性能测试的时候大概翻译了一下以便学习,今天整理一下发上来,有些地方也不知道怎么翻,就保留了原文,可能还好理解点,呵呵,水平有限,翻的不好,大 ...
- DelphiXE_画图
1.基本 DelphiXE FireMonkey 如何画图 http://www.delphitop.com/html/FireMonkey/2647.html 2. 3.
- JavaScrip 原生多文件上传及预览 兼容多浏览器
JavaScrip 原生多文件上传及预览 兼容多浏览器 html代码块 <div class="container"> <label>请选择一个图像文件:& ...
- spring boot: 组合注解与元注解
package ch2.annotation; //target/elementType用来设定注解的使用范围 import java.lang.annotation.ElementType; imp ...
- openGL 3.3+ 场景渲染
这个渲染程序是研一下学期的计算机图形学课程大作业,花了两三周学习使用了下 openGL 3.3+ 库,整合出了这个渲染程序,完成于 2013/07/05. 相对于老版本的库,新版本更开放,给了程序员更 ...
- Android开发中java.lang.RuntimeException: Unable to start activity ComponentInfo{xxx}
Android开发中java.lang.RuntimeException: Unable to start activity ComponentInfo{xxx}: java.lang.NullPoi ...
- Spring3.2.9 + JdbcTemplate 学习
applicationContext.xml <?xml version="1.0" encoding="UTF-8"?> <beans xm ...