一、原數據狀態

二、手動寫透視轉換1

三、手動寫透視轉換2

四、PIVOT(透視轉換)和UNPIVOT(逆透視轉換)詳細使用
- 使用標准SQL進行透視轉換和逆視轉換
--行列轉換 create table #demoOrders ( id int primary key identity(1,1), CompanyName nvarchar(50), ProductID int, ProductName nvarchar(50) ) insert into #demoOrders (CompanyName,ProductID,ProductName) values('公司1','1','產品1') insert into #demoOrders (CompanyName,ProductID,ProductName) values('公司1','2','產品2') insert into #demoOrders (CompanyName,ProductID,ProductName) values('公司2','2','產品2') insert into #demoOrders (CompanyName,ProductID,ProductName) values('公司2','3','產品3') insert into #demoOrders (CompanyName,ProductID,ProductName) values('公司3','3','產品3') insert into #demoOrders (CompanyName,ProductID,ProductName) values('公司4','3','產品3') insert into #demoOrders (CompanyName,ProductID,ProductName) values('公司5','4','產品4') insert into #demoOrders (CompanyName,ProductID,ProductName) values('公司6','4','產品4') insert into #demoOrders (CompanyName,ProductID,ProductName) values('公司6','5','產品5') select * from #demoOrders

透視轉換的標准SQL解決方案以一種非常直接的方式來處理轉換過程中涉及的三個階段:
1、分組階段用group by 子句實現
2、擴展階段通過在select子句中為每個目標列指定case表達式來實現,這需要事先知道每個擴展元素的取值,並為每個值指定一個單獨的case表達式。
3、聚合階段通過為每個case表達式的結果應用相關的聚合函數來實現。
解題思維步驟:
1.先找到為行列轉換的數據,分組查看數據試試:
select CompanyName,ProductName,count(*) as num from #demoOrders group by ProductName,CompanyName order by CompanyName

2.分組階段:用group by 子句以行作為分組條件,獲取行數據
select CompanyName from ( select CompanyName,ProductName,COUNT(*)as num from #demoOrders group by ProductName,CompanyName ) T group by CompanyName

3.擴展階段:找到列的數據,為每個目標列指定case表達式;聚合階段通過為每個case表達式的結果應用相關的聚合函數來實現
select CompanyName, sum(case when ProductName='產品1' then num else 0 end)[產品1], sum(case when ProductName='產品2' then num else 0 end)[產品2], sum(case when ProductName='產品3' then num else 0 end)[產品3], sum(case when ProductName='產品4' then num else 0 end)[產品4], sum(case when ProductName='產品5' then num else 0 end)[產品5] from ( select CompanyName,ProductName,COUNT(*)as num from #demoOrders group by ProductName,CompanyName ) T group by CompanyName --以下是分頁存儲過程,看看拼接sql語句字符串和執行的過程,然后把思路打開一下試試 declare @sql nvarchar(1000) set @sql='select CompanyName,'--開始設置語句 --------動態生成語句begin(開始轉成列)----- select @sql=@sql+'sum(case when ProductName='''+ProductName+''' then num else 0 end)['+ProductName+'],' from (select distinct top 100 percent ProductName from #demoOrders order by ProductName)a --------動態生成語句 end-------------------- print @sql set @sql =left(@sql,len(@sql)-1)+' from (select CompanyName,ProductName,COUNT(*)as num from #demoOrders group by ProductName,CompanyName)a group by CompanyName' print @sql --打印輸出最終執行的SQL exec(@sql) --執行SQL字符串

逆透視轉換的標准SQL解決方案要實現三個邏輯處理階段:
1、生成副本:根據來源表的每一行生成多個副本(為需要逆透視的每個列生成一個副本);用cross join(交叉聯接)來生成每一行的多個副本
2、提取元素
3、刪除不相關的交叉
--逆視數據 select CompanyName, sum(case when ProductName='產品1' then num else 0 end)[產品1], sum(case when ProductName='產品2' then num else 0 end)[產品2], sum(case when ProductName='產品3' then num else 0 end)[產品3], sum(case when ProductName='產品4' then num else 0 end)[產品4], sum(case when ProductName='產品5' then num else 0 end)[產品5] into #unpivotDemo from ( select CompanyName,ProductName,COUNT(*)as num from #demoOrders group by ProductName,CompanyName ) a group by CompanyName
1、在#unpivotDemo表和每行ProductName之間進行交叉聯接
select * from #unpivotDemo cross join (values('產品1'),('產品2'),('產品3'),('產品4'),('產品5')) as #unpivotDemo2(ProductName) --或: select * from #unpivotDemo cross join ( select '產品1' as ProductName union all select '產品2' union all select '產品3' union all select '產品4' union all select '產品5' ) as #unpivotDemo2

2.1、生成一個數據列,由它返回與當前副本所代表的產品相對應的列值
select *, case ProductName when '產品1' then 產品1 when '產品2' then 產品2 when '產品3' then 產品3 when '產品4' then 產品4 when '產品5' then 產品5 end as num from #unpivotDemo cross join (values('產品1'),('產品2'),('產品3'),('產品4'),('產品5')) as #unpivotDemo2(ProductName) --或: select *, case ProductName when '產品1' then 產品1 when '產品2' then 產品2 when '產品3' then 產品3 when '產品4' then 產品4 when '產品5' then 產品5 end as num from #unpivotDemo cross join ( select '產品1' as ProductName union all select '產品2' union all select '產品3' union all select '產品4' union all select '產品5' ) as #unpivotDemo2

2.2、提取所需的數據列
select CompanyName,ProductName, case ProductName when '產品1' then 產品1 when '產品2' then 產品2 when '產品3' then 產品3 when '產品4' then 產品4 when '產品5' then 產品5 end as num from #unpivotDemo cross join (values('產品1'),('產品2'),('產品3'),('產品4'),('產品5')) as #unpivotDemo2(ProductName) --或: select CompanyName,ProductName, case ProductName when '產品1' then 產品1 when '產品2' then 產品2 when '產品3' then 產品3 when '產品4' then 產品4 when '產品5' then 產品5 end as num from #unpivotDemo cross join ( select '產品1' as ProductName union all select '產品2' union all select '產品3' union all select '產品4' union all select '產品5' ) as #unpivotDemo2

3、0值與NULL值代表不相關的交叉,為了刪除不相關的交叉,在外部查詢中過濾掉0值與NULL值
select * from ( select CompanyName,ProductName, case ProductName when '產品1' then 產品1 when '產品2' then 產品2 when '產品3' then 產品3 when '產品4' then 產品4 when '產品5' then 產品5 end as num from #unpivotDemo cross join (values('產品1'),('產品2'),('產品3'),('產品4'),('產品5')) as #unpivotDemo2(ProductName) ) as T where num is not null and num <> 0 --或: select * from ( select CompanyName,ProductName, case ProductName when '產品1' then 產品1 when '產品2' then 產品2 when '產品3' then 產品3 when '產品4' then 產品4 when '產品5' then 產品5 end as num from #unpivotDemo cross join ( select '產品1' as ProductName union all select '產品2' union all select '產品3' union all select '產品4' union all select '產品5' ) as #unpivotDemo2 ) as T where num is not null and num <> 0

- 使用T-SQL PIVOT透視轉換和UNPIVOT逆透視轉換
pivot的使用
select CompanyName,[產品1] as 產品1,[產品2] as 產品2,[產品3] as 產品3,[產品4] as 產品4,[產品5] as 產品5 from ( --表表達式作為pivot輸入表,僅僅返回透視中用到的列 select CompanyName,ProductName,count(*) as num from #demoOrders group by ProductName,CompanyName ) as sourceTable --分組是隱含的,對表中除掉聚合和條件的列進行分組 pivot ( sum(num) --聚合函數 for ProductName in([產品1],[產品2],[產品3],[產品4],[產品5]) --准備做列名 ) as PivotTable
create table #demotable ( id int primary key identity(1,1), orderMonth int , subTotal decimal(18,2) ) insert into #demotable (orderMonth,subTotal) values(5,100.00) insert into #demotable (orderMonth,subTotal) values(6,100.00) insert into #demotable (orderMonth,subTotal) values(5,200.00) insert into #demotable (orderMonth,subTotal) values(6,200.00) insert into #demotable (orderMonth,subTotal) values(7,100.00) select * from #demotable --方式一 select id,[5] as 五月,[6] as 六月,[7] as 七月 from #demotable --基礎表作為pivot輸入表 pivot ( sum(#demotable.subTotal) for #demotable.orderMonth in([5],[6],[7]) ) as PivotTable --方式二(推薦使用表表達式作為pivot的輸入表,不要對基礎表進行操作): select id,[5] as 五月,[6] as 六月,[7] as 七月 from ( --表表達式作為pivot輸入表,僅僅返回透視中用到的列 select id,orderMonth,subTotal from #demotable ) as sourceTable --分組是隱含的,對表中除掉聚合和條件的列進行分組 pivot ( sum(subTotal) --聚合函數 for orderMonth in([5],[6],[7]) --准備做列名 ) as PivotTable drop table #demotable

unpivot的使用
create table #demotable2 ( id int, 五月 int, 六月 int, 七月 int ) insert into #demotable2 values (1,100,100,0); insert into #demotable2 values (2,200,200,200); insert into #demotable2 values (3,800,0,0); select * from #demotable2 --執行UNPIVOT select id,orderMonth,subTotal FROM #demotable2 unpivot ( subTotal for orderMonth in(五月,六月,七月) )AS UnpivotTable drop table #demotable2

練習:
create table #testtable ( id int primary key identity(1,1), t_year int , t_month int, t_amount decimal(18,1) ) insert into #testtable (t_year,t_month,t_amount) values(1991,1,1.1) insert into #testtable (t_year,t_month,t_amount) values(1991,2,1.2) insert into #testtable (t_year,t_month,t_amount) values(1991,3,1.3) insert into #testtable (t_year,t_month,t_amount) values(1992,1,2.1) insert into #testtable (t_year,t_month,t_amount) values(1992,2,2.2) insert into #testtable (t_year,t_month,t_amount) values(1992,3,2.3) --drop table #testtable select * from #testtable --//想要的結果 --year m1 m2 m3 --1991 1.1 1.2 1.3 --1992 2.1 2.2 2.3 select max(t_year) as [year],max([1]) as m1,max([2]) as m2,max([3]) as m3 from #testtable pivot ( max(t_amount) for t_month in([1],[2],[3]) ) as PivotTable group by t_year select t_amount,ColumnName,YearAndMonth from #testtable unpivot ( YearAndMonth for ColumnName in(t_year,t_month) ) as UnpivotTable --行列轉換 --解題思維步驟: --1.先找到為行列轉換的數據,查看數據試試: select t_year,t_month,t_amount from #testtable --2.找到列的數據 select (case when t_month=1 then t_amount else 0 end)[m1], (case when t_month=2 then t_amount else 0 end)[m2], (case when t_month=3 then t_amount else 0 end)[m3] from #testtable --3.以行作為分組條件,獲取行數據;兩者結合起來,答案: select t_year, max(case when t_month=1 then t_amount else 0 end)[m1], max(case when t_month=2 then t_amount else 0 end)[m2], max(case when t_month=3 then t_amount else 0 end)[m3] from #testtable group by t_year --------------------以下是sql語句字符串和執行的過程------------------------ declare @sql nvarchar(1000) set @sql='select t_year,' --------動態生成列 begin-------- select @sql=@sql+'max(case when t_month='+convert(nvarchar(20),t_month)+' then t_amount else 0 end)[m'+str(t_month,1)+'],' from (select distinct top 100 percent t_month from #testtable order by t_month) T print @sql --------動態生成列 end-------- set @sql=left(@sql,len(@sql)-1)+' from #testtable group by t_year' print @sql exec(@sql)
