我们在写Sql语句的时候没经常会遇到将查询结果行转列,列转行的需求,拼接sql字符串,然后使用执行sql字符串是比较常规的一种做法。但是这样做实现起来非常复杂,而在SqlServer2005中我们有了PIVOT函数可以快速实现行转列.




SQL server 行专列 sqlserver列转行函数_pivot行转列 汉字字符列


PIVOT函数,行转列

PIVOT函数的格式如下

PIVOT(([聚合列值]) FOR [行转列前的列名] IN([行转列后的列名1],[行转列后的列名2],[行转列后的列名3],.......[行转列后的列名N]))

  • 就是我们使用的SUM,COUNT,AVG等Sql聚合函数,也就是行转列后计算列的聚合方式。
  • [聚合列值]要进行聚合的列名
  • [行转列前的列名]这个就是需要将行转换为列的列名。
  • [行转列后的列名]这里需要声明将行的值转换为列后的列名,因为转换后的列名其实就是转换前行的值,所以上面格式中的[行转列后的列名1],[行转列后的列名2],[行转列后的列名3],......[行转列后的列名N]其实就是[行转列前的列名]每一行的值。

接下来我们造一个例子,生成一个表[shopping]有三列[week],[price],[groupId],数据和表结构如下图所示

CREATE TABLE [dbo].[Shopping]( [Week] [int] NOT NULL, [Price] [decimal](18, 0) NOT NULL, [GroupId] [int] NULL) ON [PRIMARY]GOALTER TABLE [dbo].[Shopping] ADD DEFAULT ((0)) FOR [Price]GOINSERT [dbo].[Shopping] ([Week], [Price], [GroupId]) VALUES (1, CAST(10 AS Decimal(18, 0)), 1)GOINSERT [dbo].[Shopping] ([Week], [Price], [GroupId]) VALUES (2, CAST(20 AS Decimal(18, 0)), 1)GOINSERT [dbo].[Shopping] ([Week], [Price], [GroupId]) VALUES (3, CAST(30 AS Decimal(18, 0)), 1)GOINSERT [dbo].[Shopping] ([Week], [Price], [GroupId]) VALUES (4, CAST(40 AS Decimal(18, 0)), 1)GOINSERT [dbo].[Shopping] ([Week], [Price], [GroupId]) VALUES (5, CAST(50 AS Decimal(18, 0)), 1)GOINSERT [dbo].[Shopping] ([Week], [Price], [GroupId]) VALUES (6, CAST(60 AS Decimal(18, 0)), 1)GOINSERT [dbo].[Shopping] ([Week], [Price], [GroupId]) VALUES (7, CAST(70 AS Decimal(18, 0)), 1)GO

查询表信息

select * from [Shopping]


SQL server 行专列 sqlserver列转行函数_cast函数_02

查询结果


现在我们用PIVOT函数将列[WEEK]的行值转换为列,并使用聚合函数Count(TotalPrice)来统计每一个Week列在转换前有多少行数据,语句如下所示:

select *from Shopping as C PIVOT(SUM(Price) FOR [Week] IN([1],[2],[3],[4],[5],[6],[7])) AS T


SQL server 行专列 sqlserver列转行函数_cast函数_03


可以看到:

1.PIVOT的格式:

SELECT [原表字段1,2,3…] FROM [表名]

AS [原表别名]

PIVOT( [聚合函数] ( [原表字段1] ) FOR [原表字段2] IN ( [原表2值1],[原表字段2值2]… ) ) AS [新表别名]

2.注意点:

(1)PIVOT必须列举[原表字段2的值],列举的值必须用中括号 [ ] 包含起来,就算是字符串类型也不需要单引号 ’ ’

(2)PIVOT中列举的值将作为新表的字段名称

(3)为什么会有聚合函数?此处并没有GROUP BY !GROUP BY 是隐藏的,除了语句中出现的两个 [原表字段],其他[原表字段]将被GROUP BY,这样才使得上面的PIVOT结果出现多行

(4)列举字段的这个组在原表中没有数据将以NULL值存在于PIVOT后的新表