SQL行转列 (及EAV模型获取数据)

参考文章:

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
时间: 2024-10-10 18:20:45

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

比较经典的SQL行转列+分组集联

这是一个比较经典的行转列.用较少的SQL语句,就可以实现行转列.但是此行转列需要根据业务需要,进行二次开发,根据您的需要进行定制和或重写. 下面就简单聊聊这种形式吧 1.建表脚本 CREATE TABLE [dbo].[Table_1]( [a] [int] NOT NULL,--目标列名 [b] [uniqueidentifier] NOT NULL,--目标数据 [c] [nchar](10) NOT NULL--筛选条件) ON [PRIMARY] GO ALTER TABLE [dbo]

SQL 行转列查询汇总

SQL行转列汇总 PIVOT 用于将列值旋转为列名(即行转列),在 SQL Server 2000可以用聚合函数配合CASE语句实现 PIVOT 的一般语法是:PIVOT(聚合函数(列) FOR 列 in (…) )AS P 注意:PIVOT.UNPIVOT是SQL Server 2005 的语法,使用需修改数据库兼容级别(在数据库属性->选项->兼容级别改为 90 ) SQL2008 中可以直接使用 完整语法: table_source PIVOT( 聚合函数(value_column) F

Sql 行转换为列 以及列转换为行的心得

这是 创建数据库的脚本文件 CREATE TABLE [dbo].[stu]( [学号] [nvarchar](255) NOT NULL, [姓名] [nvarchar](255) NULL, [性别] [nvarchar](255) NULL, [专业] [nvarchar](255) NULL, [院系] [nvarchar](255) NULL ) ON [PRIMARY] GO INSERT [dbo].[stu] ([学号], [姓名], [性别], [专业], [院系]) VALU

SQL 行转列

---1.最简单的行转列/* 问题:假设有张学生成绩表(tb)如下:姓名 课程 分数张三 语文 74张三 数学 83张三 物理 93李四 语文 74李四 数学 84李四 物理 94 想变成(得到如下结果): 姓名 语文 数学 物理 李四 74   84   94张三 74   83   93*/--测试用 IF OBJECT_ID('[tb]') IS NOT NULL DROP TABLE [tb] GO create table tb(姓名 varchar(10) , 课程 varchar(

SQL行转列汇总

SQL行转列汇总 PIVOT 用于将列值旋转为列名(即行转列),在 SQL Server 2000可以用聚合函数配合CASE语句实现 PIVOT 的一般语法是:PIVOT(聚合函数(列) FOR 列 in (…) )AS P 注意:PIVOT.UNPIVOT是SQL Server 2005 的语法,使用需修改数据库兼容级别(在数据库属性->选项->兼容级别改为   90 ) SQL2008 中可以直接使用 完整语法: table_source PIVOT( 聚合函数(value_column)

sql 行转列总结

原文:sql 行转列总结 PIVOT UNPIVOT的用法 PIVOT用于将列值旋转为列名(即行转列),在SQL Server 2000可以用聚合函数配合CASE语句实现 PIVOT的一般语法是:PIVOT(聚合函数(列) FOR 列 in (-) )AS P 完整语法: table_source PIVOT( 聚合函数(value_column) FOR pivot_column IN(<column_list>) ) UNPIVOT用于将列明转为列值(即列转行),在SQL Server 2

sql 行转列 PIVOT 列转行 UNPIVOT

原文:sql 行转列 PIVOT 列转行 UNPIVOT 一: 现有表一(t_table1),想转为表二(t_table2)的格式. 表一: 年 公司 收入 2013 公司1 12 2013 公司2 22 2013 公司3 32 2012 公司1 42 2012 公司2 52 2012 公司3 62 表二: 年 公司1 公司2 公司3 2012 42 52 62 2013 12 22 32 可使用sql2005之后提供的PIVOT 具体操作如下: select * from   t_table1

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

转载:http://www.cnblogs.com/newwind521/archive/2010/11/25/1887203.html sql 行专列 列转行 普通行列转换 /* 标题:普通行列转换(version 2.0) 作者:爱新觉罗.毓华 时间:2008-03-09 地点:广东深圳 说明:普通行列转换(version 1.0)仅针对sql server 2000提供静态和动态写法,version 2.0增加sql server 2005的有关写法.  问题:假设有张学生成绩表(tb)如

SQL 行转列和列转行

行列互转,是一个经常遇到的需求.实现的方法,有case when方式和2005之后的内置pivot和unpivot方法来实现. 在读了技术内幕那一节后,虽说这些解决方案早就用过了,却没有系统性的认识和总结过.为了加深认识,再总结一次. 行列互转,可以分为静态互转,即事先就知道要处理多少行(列);动态互转,事先不知道处理多少行(列). --创建测试环境 USE tempdb; GO IF OBJECT_ID('dbo.Orders') IS NOT NULL DROP TABLE dbo.Orde