情景简介

学校里面记录成绩,每个人的选课不一样,而且以后会添加课程,所以不需要把所有课程当作列。数据库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. CentOS 安装 Zabbix

    一.安装 centos7 网易下载 http://mirrors.163.com/centos/7.2.1511/isos/x86_64/CentOS-7-x86_64-DVD-1511.torren ...

  2. Classloader机制

    1.概述? 类加载器:负责.class文件加载到内存中,并为之生成对应的Class对象,也就是字节码对象.这样就可以使用这个类中的成员变量和方法了.而被加载到内存中的class文件就会变成class对 ...

  3. shell运行java/Jar 脚本

    1.Shell执行/调用Java/Jar程序 #!/bin/bash JAVA_HOME="$HOME/jdk" BASE_DIR=`dirname $0` if [ " ...

  4. 关于发邮件报错535 Error:authentication failed&553 authentication is required

    553 authentication is required:这个错误的意思是你必须需要认证. 也就是说,你连接smtp服务器的时候必须使用密码来连接:下面代码红色那句 代码: @Override p ...

  5. scapy学习笔记(2)

    一.包 包(Packet)是TCP/IP协议通信传输中的数据单位,一般也称“数据包”.其主要由“目的IP地址”.“源IP地址”.“净载数据”等部分构成,包括包头和包体,包头是固定长度,包体的长度不定, ...

  6. 阿里云服务器windows server2008r2+tomcat8.0+nginx1.12

    弄了两天的nginx,从了解开始,可能是我理解能力太差了,惭愧惭愧!但是还好看了一些大神的文章总算有点眉目了,此篇用来当作自己的笔记,大家看不懂,勿喷,但是如果有问题,直接回复,我可以给你解答一下,前 ...

  7. 碰到错误Could not load the Tomcat server configuration at \Servers\MyEclipse Tomcat v8.5-config. The Servers project is closed.

    本人用的myeclipse是2017版. 可能解决的方法是: 双击MyEclipse Tomcat v8.5,然后就会弹出以下窗口,

  8. 使用Blob获取图片并二进制显示实例页面

    HTML代码: <div id="forAppend" class="demo"></div> JS代码: var eleAppend ...

  9. Bellman-Ford算法 O(NE)

    Bellman-Ford算法 O(NE) 思路:枚举n-1次所有边,通过枚举所有边,将所有和已知点相连的点都设为已知,初始时起点为已知点. ;i<=n-;i++){ //n-1是次数,枚举n-1 ...

  10. Ajax-快速上手前后端交互

    Ajax 在之前自己也有总结过关于Ajax的笔记,各种的懵圈,通过一次项目和几次的总结和分享,我对Ajax终于算是有了一定的理解和自己的见解.相信大家见过和度过了很多的关于Ajax的什么前世今生.大刀 ...