参考文章:

http://www.williamsang.com/archives/1508.html

情景简介

学校里面记录成绩,每个人的选课不一样,而且以后会添加课程,所以不需要把所有课程当作列。数据库grade里面数据如下图,假定每个人姓名都不一样,作为主键。本文以MySQL为基础,其他数据库会有些许语法不同。

数据库数据:

处理后效果:

下面介绍三种方法:

方法一:

1
2
3
4
5
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

方法二:

1
2
3
4
5
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

方法三:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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();这是错误的。调试的时候如果写错了,只能手动删除了,也没找到好方法。

参考资料:


2013-8-8更新:

方法二还可以使用IF语句。
如下所示:

1
2
3
4
5
SELECT name,
SUM(IF (course = '语文' , score , null ) ) as '语文',
SUM(IF (course = '数学' , score , null ) ) as '数学',
SUM(IF (course = '英语' , score , null ) ) as '英语 '
FROM grade GROUP BY name

IF(expr1,expr2,expr3),如果expr1是TRUE(expr1<>0且expr1<>NULL),那么IF()返回expr2,否则它返回expr3。IF()返回一个数字或字符串值,取决于它被使用的上下


方法四:使用多次 自连接 (每多一行转列都多一次inner join)

SELECT `main_table`.*,`table_name`.`value` AS `name`,`table_name2`.`value` AS `url_path`
FROM `catalog_category_entity` AS `main_table`
INNER JOIN `catalog_category_entity_varchar` AS `table_name` ON `table_name`.`entity_id`=`main_table`.`entity_id`
INNER JOIN `catalog_category_entity_varchar` AS `table_name2` ON `table_name2`.`entity_id`=`main_table`.`entity_id`
WHERE 1=1
AND (`table_name`.`attribute_id` = (41))
AND (`table_name2`.`attribute_id` = (57))
AND (`main_table`.`parent_id` = (2))
GROUP BY main_table.entity_id

SQL行转列 (及EAV模型获取数据)的更多相关文章

  1. SQL 行转列和列转行

    SQL 行转列和列转行 行列互转,是一个经常遇到的需求.实现的方法,有case when方式和2005之后的内置pivot和unpivot方法来实现. 在读了技术内幕那一节后,虽说这些解决方案早就用过 ...

  2. Ms sql行转列。汇总

    SQL行转列汇总 PIVOT 用于将列值旋转为列名(即行转列),在 SQL Server 2000可以用聚合函数配合CASE语句实现 PIVOT 的一般语法是:PIVOT(聚合函数(列) FOR 列 ...

  3. sql 行专列 列转行 普通行列转换

    转载:http://www.cnblogs.com/newwind521/archive/2010/11/25/1887203.html sql 行专列 列转行 普通行列转换 /* 标题:普通行列转换 ...

  4. sql 行转列 PIVOT 列转行 UNPIVOT

    原文:sql 行转列 PIVOT 列转行 UNPIVOT 一: 现有表一(t_table1),想转为表二(t_table2)的格式. 表一: 年 公司 收入 2013 公司1 12 2013 公司2 ...

  5. sql 行转列总结

    原文:sql 行转列总结 PIVOT UNPIVOT的用法 PIVOT用于将列值旋转为列名(即行转列),在SQL Server 2000可以用聚合函数配合CASE语句实现 PIVOT的一般语法是:PI ...

  6. SQL行转列,列转行

    SQL 行转列,列转行 行列转换在做报表分析时还是经常会遇到的,今天就说一下如何实现行列转换吧. 行列转换就是如下图所示两种展示形式的互相转换 行转列 假如我们有下表: SELECT * FROM s ...

  7. SQL行转列和列转行

    行列互转,是一个经常遇到的需求.实现的方法,有case when方式和2005之后的内置pivot和unpivot方法来实现. 在读了技术内幕那一节后,虽说这些解决方案早就用过了,却没有系统性的认识和 ...

  8. sql行转列和列转行(转)

    行列互转,是一个经常遇到的需求.实现的方法,有case when方式和2005之后的内置pivot和unpivot方法来实现. 在读了技术内幕那一节后,虽说这些解决方案早就用过了,却没有系统性的认识和 ...

  9. sql 行转 列, 列转行

    行列互转 复制代码 create table test(id ),quarter int,profile int) insert into test values(,,) insert into te ...

随机推荐

  1. CAD控件的超链接事件(网页版)

    _DMxDrawXEvents::HyperlinkClick 有超连接的实体被点击了. 参数 说明 IDispatch* pEntity IMxDrawEntity,被点击的实体 DOUBLE dX ...

  2. 解决wpf popup控件遮挡其他程序的问题

    public class PopupNonTopmost : Popup { public static DependencyProperty TopmostProperty = Window.Top ...

  3. dubbo 多连接,多线程池.

    1. consumer 多连接 Dubbo protocol options: <dubbo:protocolname=“dubbo” port=“9090” server=“netty” cl ...

  4. javaEE(4)_response、request对象

    一.简介 Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象.和代表响应的response对象.request和response对象即然代表请求和响应 ...

  5. mysqldump 备份导出数据排除某张表或多张表

    可以使用--ignore-table=dbname.tablename 忽略一张表 /usr/bin/mysqldump --set-gtid-purged=OFF -h127.0.0.1 -uroo ...

  6. tkinter学习-事件绑定与窗口

    阅读目录: 事件绑定 Toplevel组件 标准对话框 事件绑定: 说明:对于每个组件来说,可以通过bind()方法将函数或方法绑定到具体的事件上. 事件序列: 说明:用户需要使用bind()方法将具 ...

  7. python爬虫基础07-selenium大全1/8-安装和简单使用

    Selenium笔记(1)安装和简单使用 本文集链接:https://www.jianshu.com/nb/25338984 简介 Selenium是一个用于Web应用程序测试的工具. Seleniu ...

  8. I2C驱动框架(一)

    参考:I2C子系统之内核中I2C子系统的结构 结合vmlinux.lds和Makefile可确定i2c初始化函数的执行顺序如下: 1./dricer/i2c/i2c-core.c中的函数:i2c_in ...

  9. 对uboot中CFG_和CONFIG_的理解

    CONFIG_用于选择CPU   SOC 板子的类型,系统时钟,设备驱动driver驱动等 CFG_用于设置malloc缓冲池的大小,偏移地址部分的定义,uboot的提示符,uboot的加载地址,fl ...

  10. shell基础学习-难点重点学习

    来自shell13问 -e : 啟用反斜線控制字符的轉換(參考下表) -E:關閉反斜線控制字符的轉換(預設如此) -n : 取消行末之換行符號(與 -e 選項下的 \c 字符同意) 要取消一個变量,在 ...