透視數據是一種把數據從行的狀態旋轉爲列的狀態的處理。每一個透視轉換將涉及分組、擴展及聚合三個邏輯處理階段,每一個階段都有相關的元素:分組階段處理相關的分組或行元素,擴展階段處理相關的擴展或列元素,聚合階段處理相關的聚合元素和聚合函數。如今假設有一張表數據以下:sql
我如今須要查詢出下面的結果:函數
需求分析:須要在結果中爲每個僱員生成一行記錄,這就須要對Orders表中的行按照其empid列進行分組;從結果看,還須要爲每個客戶生成一個不一樣的結果列,那麼擴展元素就是custid列;最後還須要對數據進行聚合(本例中爲SUM)。如下代碼是使用標準SQL進行透視轉換:測試
SELECT empid, SUM(CASE WHEN custid = 'A' THEN qty END) AS A, SUM(CASE WHEN custid = 'B' THEN qty END) AS B, SUM(CASE WHEN custid = 'C' THEN qty END) AS C, SUM(CASE WHEN custid = 'D' THEN qty END) AS D FROM dbo.Orders GROUP BY empid;
※※※※※※ 補充,若是要轉爲動態的查詢,即不固定對A、B、C、D進行透視轉換呢?請看下面:spa
先分析,若是是動態查詢,那麼確定須要拼湊SQL語句,即對「SUM(CASE WHEN custid = 'A' THEN qty END) AS A,」這一部分進行拼湊。首先想到要用「SELECT custid FROM [tempdb].[dbo].[Orders] GROUP BY custid」把A、B、C、D等數據GROUP BY 查出來,而後對這個數據集使用遊標循環拼湊出SQL語句,可是如今還有更方便的方法。先看一個測試:code
DECLARE @temp NVARCHAR(50); SET @temp = ''; SELECT @temp = @temp + ',' + custid FROM ( SELECT custid FROM [tempdb].[dbo].[Orders] GROUP BY custid ) AS T; PRINT @temp;
上面這段SQL會輸出「,A,B,C,D」,這說明了想循環讀取數據集並賦值不必定要用遊標,別忘了SELECT也是能夠賦值的!因此透視轉換的動態SQL以下:blog
DECLARE @sql NVARCHAR(800); SET @sql = 'SELECT empid'; SELECT @sql = @sql + ',SUM(CASE WHEN custid=''' + custid + ''' THEN qty END) AS ' + QUOTENAME(custid) FROM ( SELECT custid FROM [tempdb].[dbo].[Orders] GROUP BY custid ) AS T SET @sql = @sql + ' FROM dbo.Orders GROUP BY empid'; EXEC(@sql);
下面是使用T-SQL PIVOT運算符進行透視轉換。SQL Server 2005引入了一個T-SQL特有的表運算符PIVOT,PIVOT運算符一樣涉及三個邏輯處理階段(分組、擴展和聚合)。注意,通常不直接把PIVOT運算符應用到源表,而是將其應用到一個表表達式(該表表達式只包含透視轉換須要的3種元素,不包含其餘屬性):qt
SELECT empid, A, B, C, D FROM (SELECT empid, custid, qty FROM dbo.Orders) AS D PIVOT(SUM(qty) FOR custid IN(A, B, C, D)) AS P;
上面代碼中PIVOT操做符並無直接操做Orders表,而是對一個名爲D的派生表進行操做,該派生表只包含透視轉換元素empid、custid、qty。class
需求以下,原數據以下:擴展
如今須要獲得這樣的數據:循環
使用標準SQL進行逆透視轉換。逆透視轉換的標準SQL解決方案很是明確地要實現3個邏輯處理階段:生成副本、提取元素和刪除不相關的交叉。
SELECT empid, custid, CASE custid WHEN 'A' THEN A WHEN 'B' THEN B WHEN 'C' THEN C WHEN 'D' THEN D END AS qty FROM dbo.EmpCustOrders CROSS JOIN (VALUES('A'),('B'),('C'),('D')) AS Custs(custid);
執行結果以下:
若是還想進一步過濾掉含有null值的數據,則能夠這樣:
SELECT * FROM (SELECT empid, custid, CASE custid WHEN 'A' THEN A WHEN 'B' THEN B WHEN 'C' THEN C WHEN 'D' THEN D END AS qty FROM dbo.EmpCustOrders CROSS JOIN (VALUES('A'),('B'),('C'),('D')) AS Custs(custid)) AS D WHERE qty IS NOT NULL;
使用T-SQL的UNPIVOT運算符進行逆透視轉換:
SELECT empid, custid, qty FROM dbo.EmpCustOrders UNPIVOT(qty FOR custid IN(A, B, C, D)) AS U;
GROUPING SETS從屬子句:
SELECT empid, custid, SUM(qty) AS sumqty FROM dbo.Orders GROUP BY GROUPING SETS ( (empid, custid), (empid), (custid), () );
CUBE從屬子句
SELECT empid, custid, SUM(qty) AS sumqty FROM dbo.Orders GROUP BY CUBE(empid, custid);