设为首页 加入收藏

TOP

锋利的SQL-SQLServer的表旋转(行列转换)(二)
2014-11-24 02:54:41 来源: 作者: 【 】 浏览:10
Tags:锋利 SQL-SQLServer 旋转 行列 转换
需要注意的是FROM的含义,其表示从经PIVOT关系运算符得到的pvt结果集中检索数据,而不是从Orders或派生表O1中检索数据。

在SQL Server2005之前,要进行行列转换比较烦琐,你需要考虑源表中行与结果集中行的关系,属性列中的每个唯一值在结果集中都需要一个列。像上面表9-7中的Orders表由于包含3个月份的数据,因此在SELECT列表中需要包含3个表达式,分别用于提取3个月份中的数据。下面语句的查询结果与表9-9相同,请读者自己分析下面的语句。

SELECT ProductID,

SUM(CASE WHEN OrderMonth = 1 THEN SubTotal END) AS Jan,

SUM(CASE WHEN OrderMonth = 2 THEN SubTotal END) AS Feb,

SUM(CASE WHEN OrderMonth = 3 THEN SubTotal END) AS Mar

FROM (SELECT ProductID,

MONTH(OrderDate) AS OrderMonth,

SubTotal AS SubTotal

FROMOrders) AS O1

GROUP BY ProductID;

9.4.2 UNPIVOT运算符

UNPIVOT与PIVOT执行几乎完全相反的操作,将列转换为行。但是,UNPIVOT并不完全是PIVOT的逆操作,由于在执行PIVOT过程中,数据已经被进行了分组汇总,所以使用UNPIVOT并不会重现原始表值表达式的结果。假设表9-9所示的结果集存储在一个名为MyPvt的表中,现在需要将列Jan、Feb和Mar转换到对应于相应产品ID的行值(即返回到表9-10所示的格式)。这意味着必须另外标识两个列,一个用于存储月份,一个用于存储销售额。为了便于理解,仍旧分别将这两个列命名为OrderMonth和SubTotal。

下面的语句首先创建MyPvt表,然后将查询数据插入到表中。

CREATE TABLE MyPvt

(

ProductID int NOT NULL,

Jan money,

Feb money,

Mar money

);

INSERT INTO MyPvt(ProductID, Jan, Feb, Mar)

SELECT ProductID,

[1] AS Jan,

[2] AS Feb,

[3] AS Mar

FROM (SELECT ProductID,MONTH(OrderDate) AS OrderMonth, SubTotal

FROM Orders) AS O1

PIVOT

(

SUM(SubTotal)

FOR OrderMonth IN ([1], [2], [3])

) AS Pvt

ORDER BY ProductID;

下面的语句执行UNPIVOT,将得到表9-12所示的查询结果。

SELECT ProductID,OrderMonth, SubTotal

FROM MyPvt

UNPIVOT

(

SubTotal FOR OrderMonth IN (Jan, Feb, Mar)

)AS UnPvt;

表9-12 UNPIVOT得到的查询结果

ProductID

OrderMonth

SubTotal

1

Jan

300.00

1

Feb

100.00

1

Mar

100.00

2

Jan

100.00

2

Mar

100.00

3

Feb

200.00

3

Mar

100.00

4

Mar

100.00

上面的语句将按下面的步骤获得输出结果集:

首先建立一个临时结果集的结构,该结构中包含MyPvt表中除IN (Jan, Feb, Mar)之外的列,以及SubTotalFOR OrderMonth中指定的属性值列(SubTotal)和属性列(OrderMonth)。

然后将在MyPvt中逐行检索数据,将表的列名称放入OrderMonth列中,将相应的值放入到SubTotal列中。

由于在PIVOT时为列指定了别名,所以在UNPIVOT后,OrderMonth列中的月份使用的是英文简称,而不是表9-10所示的格式。要得到表9-10所示的格式,可以在查询语句中使用CASE表达式来解决这个问题,参考下面的语句:

SELECT ProductID,

CAST(CASE

WHEN OrderMonth ='Jan' THEN '1'

WHEN OrderMonth ='Feb' THEN '2'

WHEN OrderMonth ='Mar' THEN '3'

END AS int) AS OrderMonth,

SubTotal

FROM MyPvt

UNPIVOT

(

SubTotalFOR OrderMonth IN (Jan, Feb, Mar)

)AS UnPvt;

在SQL Server2005之前,则应当使用下面的语句:

SELECT * FROM

(SELECTProductID,1 AS OrderMonth, Jan AS SubTotal

FROMMyPvt

UNION ALL

SELECTProductID,2 AS OrderMonth, Feb

FROMMyPvt

UNION ALL

SELECT ProductID,3 AS OrderMonth, Mar

FROMMyPvt) AS O

WHERE SubTotal IS NOT NULL;

9.4.3 CASE表达式在9.4节我们介绍了使用PIVOT运算符进行表行列转换的方法,有效解决了表的数据存储和方便阅读的矛盾问题,本节将提供另外的一种转换方式。这是在做一个考试系统时遇到的问题,下面是是创建示例表的语句。表中存放着学生每次各科的考试成绩。

CREATE TABLE exams

(stu_name char(10) NOT NULL,

exam_datedate NOT NULL,

exam_subchar(10) NOT NULL,

exam_scoreint);

INSERT INTO exams

VALUES ('张三', '2009-06-20', '语文', 90),

('张三', '2009-06-20', '数学', 95),

('张三', '2009-06-20', '英语', 100),

('张三', '2009-09-20', '语文', 85),

('张三', '2009-09-20', '数学', 90),

('张三', '2009-09-20', '英语', 98),

('李四', '2009-06-20', '语文', 80),

('李四', '2009-06-20', '数学', 85),

('李四', '2009-06-20', '英语', 90),

('李四', '2009-09-20', '语文', 75),

('李四', '2009-09-20', '数学', 80),

('李四', '2009-09-20', '英语', 88);

现在要获得如表12-23所示的格式,每个学生按考试日期在表中占一行。

表12-23 转换后结果

stu_name

exam_date

语文

数学

英语

张三

2009-06-20

90

95

100

张三

2009-09-20

85

90

98

李四

2009-06-20

80

85

90

李四

2009-09-20

75

80

88

在许多情况下,都可以使用CASE表达式将表的行转换为列,这是一个非常有用的技巧。参考下面的语

首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇C#同步SQLServer数据库中的数据--.. 下一篇SQL语句行列转换两种方法case .....

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

·Java多线程基础 - 华 (2025-12-24 13:20:10)
·深入解读Java多线程 (2025-12-24 13:20:08)
·Spring Boot 中文文档 (2025-12-24 13:20:04)
·如何理解智能指针? (2025-12-24 12:48:26)
·c++是否应避免使用普 (2025-12-24 12:48:23)