情景简介

学校里面记录成绩,每个人的选课不一样,而且以后会添加课程,所以不需要把所有课程当作列。数据库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问题: 行转列,列转行的更多相关文章

  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 ), --学生名称 ...

  10. 在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= ...

随机推荐

  1. 【转载】丑数humble numbers

    转载地址:http://blog.csdn.net/qwerty_xk/article/details/12749961 题:只有2 3 5 这三个因子的数,求第1500个   设1为第一个丑数,求第 ...

  2. freemarker入门实例与源码研究准备工作

    首先去freemarker官网下载源码jar包,本文是基于freemarker-2.3.21.tar.gz进行研究的.解压源码包,找到freemarker的源码部分导入eclipse工程中.需要注意的 ...

  3. Apache Phoenix的Array类型

    Apache Phoenix支持JDBC ARRAY类型,任何原生的数据类型就可以在ARRAY中使用.下面我介绍一下在创建的表中使用ARRAY类型. 先看一下创建表的SQL语句: CREATE TAB ...

  4. HDU 4000 Fruit Ninja (树状数组+反向思维)

    题意:给你一串数且每个数都不同,问你(x,y,z)出现 x<z<y 的总次数 首先我们直接想的话不能使用O(n*log2 n)解决,所以可以正难则反 可以求得x<(y,z)的值,减去 ...

  5. 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 ...

  6. 【转】java中静态方法和非静态方法的存储

    将某 class 产生出一个 instance 之后,此 class 所有的 instance field 都会新增一份,那么所有的 instance method 是否也会新增一份?答案是不会,我们 ...

  7. 使用 ActiveMQ 创建 Java 应用

    本章重点 Java 应用中内嵌 ActiveMQ 使用 Spring 内嵌 ActiveMQ 创建请求/响应应用 使用 Spring 构建 JMS 客户端

  8. 51nod 1672 贪心/队列

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1672 1672 区间交 基准时间限制:1 秒 空间限制:131072 K ...

  9. Linq练习题

    1 . 查询 Student 表中的所有记录的 Sname . Ssex 和 Class 列. select sname,ssex,class from student Linq:     from ...

  10. python--pycharm汉化

    一.准备工具 1.pycharm软件 2.汉化包 二.解压汉化包 三.将resources_cn.jar复制到pycharm文件中lib目录下 四.重新打开pycharm