筆記-Microsoft SQL Server 2008技術內幕:T-SQL語言基礎-07 透視、逆透視及分組集

透視轉換

透視數據是一種把數據從行的狀態旋轉爲列的狀態的處理。每一個透視轉換將涉及分組、擴展及聚合三個邏輯處理階段,每一個階段都有相關的元素:分組階段處理相關的分組或行元素,擴展階段處理相關的擴展或列元素,聚合階段處理相關的聚合元素和聚合函數。如今假設有一張表數據以下: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);
相關文章
相關標籤/搜索