行轉列,是SQL中經常會遇到的一個問題,並且分為靜態轉換和動態轉換,所謂靜態轉換即在轉換的行數已知或固定;動態轉換則為轉換的行數不固定。
轉換的方法一般采用case when語句或pivot(MSSQL 2005及以上版本)來實現。
首先來看靜態轉換:先准備一下測試數據,使用如下SQL語句直接生成:
If Exists (Select * From sysobjects Where
id = OBJECT_ID('Sales') and OBJECTPROPERTY(id, 'IsUserTable') = 1)
Begin
Drop Table Sales
EndCreate Table Sales(
Name nvarchar(10),
Product nvarchar(12),
Quantity int)Insert Into Sales(Name,Product,Quantity)
Values('Leo','Apple',300),
('Leo','Orange',23),
('Amy','Apple',432),
('Amy','Banana',45),
('Leo','Banana',74),
('Tomy','Apple',57),
('Tomy','Orange',92),
('Tim','Apple',76),
('Tim','Banana',45),
('Tim','Orange',159),
('Amy','Orange',610),
('Alice','Apple',245),
('Alice','Banana',342),
('Alice','Orange',138)
Go
運行后生成一個Sales表,數據如下:
現在要以商品名稱(Product)的記錄作為列,按照姓名來統計賣出的數量,如果某人未賣出某商品,則用“NULL”表示,即生成如下的格式:
分別用case when和pivot解決方法如下:
--case when方案
Select Name,
sum(Case When Product='Apple' Then Quantity Else NULL End) as Apple,
sum(Case When Product='Banana' Then Quantity Else NULL End) as Banana,
sum(Case When Product='Orange' Then Quantity Else NULL End) as Orange
From Sales
Group By Name--pivot方案 sql 2005及以上版本
Select * From Sales
PIVOT
(
SUM(Quantity) For Product in(Apple,Banana,Orange)
) as pvt
以上是靜態方案,如果有一天商品又增加了strawberry,pear等,如果要實現之前的結果,按照上面的方案就又要手動去修改SQL語句,增加兩種商品列,有沒有一勞永逸的解決方案呢,答案當然有,就是動態SQL,結合上面的SQL語句可以看出,如果在case when中可以先找到所有的商品,然后循環生成case when語句就可以解決了;在pivot解決方案中只要將所有商品記錄生成一個以“,”連接的字符串。
具體的實現語句如下:
--case when方案
Declare @sql varchar(8000)
Set @sql='Select Name'
Select @sql=@sql+' ,sum(Case When Product='''+Product+''' Then Quantity Else NULL End) as '+Product+''
From (Select DISTINCT Product From Sales) As t --變量遍歷賦值
Set @sql=@sql+' From Sales Group By Name'
exec(@sql)--pivot方案 sql 2005及以上版本
Declare @sql varchar(8000)
Set @sql=(Select DISTINCT ','+Product From Sales FOR XML PATH(''))
Set @sql=STUFF(@sql,1,1,'')
Set @sql='Select * From Sales
PIVOT
(
SUM(Quantity) For Product in('+@sql+')
) as pvt'
exec(@sql)
現在隨意新增商品都可以自動生成我們想要的結果了。


