在 SELECT 查询中使用透视

  SQL Server 2005 及后续版本可以使用 PIVOT 和 UNPIVOT 关系运算符将表值表达式更改为另一个表。http://technet.microsoft.com/zh-cn/library/ms177410(v=sql.105).aspx

  PIVOT 通过将表达式某一列中的唯一值转换为输出中的多个列来旋转表值表达式,并在必要时对最终输出中所需的任何其余列值执行聚合。

  UNPIVOT 与 PIVOT 执行相反的操作,将表值表达式的列转换为列值。


一、PIVOT

1. 语法

PIVOT 提供的语法比一系列复杂的 SELECT...CASE 语句中所指定的语法更简单和更具可读性。

SELECT <非透视的列>,

   [第一个透视的列] AS <列名称>,

   [第二个透视的列] AS <列名称>,

   ...

   [最后一个透视的列] AS <列名称>,

FROM

   (<生成数据的 SELECT 查询>)

   AS <源查询的别名>

PIVOT

(

   <聚合函数>(<要聚合的列>)

FOR

[<包含要成为列标题的值的列>]

   IN ( [第一个透视的列], [第二个透视的列],

   ... [最后一个透视的列])

) AS <透视表的别名>

<可选的 ORDER BY 子句>;


2. 示例

  下面的代码示例根据DaysToManufacture的值生成一个只有两列的表。

SELECT DaysToManufacture, AVG(StandardCost) AS AverageCost

FROM Product

GROUP BY DaysToManufacture;


  下面的代码则将将行转为列,生成一个只有一行的表。DaysToManufacture的值作为列标题,因此这个表一共有6列,列名分别为Cost_Sorted_By_Production_Days、0、1、2、3、4

SELECT 'AverageCost' AS Cost_Sorted_By_Production_Days,

[0], [1], [2], [3], [4]

FROM

(SELECT DaysToManufacture, StandardCost

   FROM Production.Product) AS SourceTable

PIVOT

(

AVG(StandardCost)

FOR DaysToManufacture IN ([0], [1], [2], [3], [4])

) AS PivotTable;


3. 复杂的示例

  下例查询 PurchaseOrderHeader 表以确定由某些特定雇员所下的采购订单数。EmployeeID 列返回的唯一值自行变成了最终结果集中的字段。因此,在透视子句中指定的每个 EmployeeID 号都有相应的一列:在本例中为雇员 164、198、223、231 和 233。PurchaseOrderID 列作为值列,将根据此列对最终输出中返回的列(称为分组列)进行分组。在本例中,通过 COUNT 函数聚合分组列。请注意,将显示一条警告消息,指出为每个雇员计算 COUNT 时未考虑显示在 PurchaseOrderID 列中的任何空值。

SELECT VendorID, [250] AS Emp1, [251] AS Emp2, [256] AS Emp3, [257] AS Emp4, [260] AS Emp5

FROM

(SELECT PurchaseOrderID, EmployeeID, VendorID

FROM Purchasing.PurchaseOrderHeader) p

PIVOT

(

COUNT (PurchaseOrderID)

FOR EmployeeID IN

( [250], [251], [256], [257], [260] )

) AS pvt

ORDER BY pvt.VendorID;


二、UNPIVOT

  UNPIVOT 将与 PIVOT 执行几乎完全相反的操作,将列转换为行。假设以上示例中生成的表在数据库中存储为 pvt,并且您需要将列标识符 Emp1、Emp2、Emp3、Emp4 和 Emp5 旋转为对应于特定供应商的行值。这意味着必须标识另外两个列。包含要旋转的列值(Emp1、Emp2...)的列将被称为 Employee,将保存当前位于待旋转列下的值的列被称为 Orders。这些列分别对应于 Transact-SQL 定义中的 pivot_column 和 value_column。以下为该查询。

SELECT VendorID, Employee, Orders

FROM

  (SELECT VendorID, Emp1, Emp2, Emp3, Emp4, Emp5

  FROM pvt) p

UNPIVOT

  (Orders FOR Employee IN

     (Emp1, Emp2, Emp3, Emp4, Emp5)

)AS unpvt;


  请注意,UNPIVOT 并不完全是 PIVOT 的逆操作。PIVOT 会执行一次聚合,从而将多个可能的行合并为输出中的单个行。而 UNPIVOT 不会重现原始表值表达式的结果,因为行已经被合并了。另外,UNPIVOT 的输入中的空值不会显示在输出中,而在执行 PIVOT 操作之前,输入中可能有原始的空值。


本文出自 “我们一起追过的MSSQL” 博客,谢绝转载!

你可能感兴趣的:(sql,透视)