正如前面提到的那样,PIVOT 运算符作用于由 table_expression 返回的虚拟表,而不是作用于 select_list 中的列。select_list 在 PIVOT 运算符执行它的操作之后计算,并且只能引用 group_by_list 和 column_list。这就是在 select_list 中不再识别 ITM 别名的原因。如果您了解这一点,您就会意识到,应当向 PIVOT 提供一个只包含您希望施加作用的列的 table_expression。这包括分组列(只有 itemid
的一个实例,外加 itemtype 、whenmade 和 initialprice )、枢轴列 (attribute ) 和值列 (value )。您可以通过使用 CTE 或派生表做到这一点。以下是一个使用 CTE 的示例:
WITH PNT AS ( SELECT ITM.*, ATR.attribute, ATR.value FROM AuctionItems AS ITM JOIN ItemAttributes AS ATR ON ITM.itemid = ATR.itemid WHERE ITM.itemtype = 'Painting' ) SELECT * FROM PNT PIVOT ( MAX(value) FOR attribute IN([artist], [name], [type], [height], [width]) ) AS PVT
以下为结果集:itemid itemtype whenmade initialprice artist name type height width ------ -------- -------- ------------ ---------------- ---------------- ---- ------ ----- 5 Painting 1873 8000000.0000 Claude Monet Field of Poppies Oil 19.62 25.62 6 Painting 1889 8000000.0000 Vincent Van Gogh The Starry Night Oil 28.75 36.25
以下是一个使用派生表的示例:SELECT * FROM (SELECT ITM.*, ATR.attribute, ATR.value FROM AuctionItems AS ITM JOIN ItemAttributes AS ATR ON ITM.itemid = ATR.itemid WHERE ITM.itemtype = 'Painting') AS PNT PIVOT ( MAX(value) FOR attribute IN([artist], [name], [type], [height], [width]) ) AS PVT
当您希望生成交叉分析报表以总结数据时,还可以使用 PIVOT。例如,使用 AdventureWorks 数据库中的 Purchasing.PurchaseOrderHeader 表(假设您希望返回每个雇员使用每个购买方法获得的定单数量,并且用购买方法 ID 作为列的枢轴)。请记住,您只应当向 PIVOT 运算符提供相关数据。您可以使用派生表并编写以下查询:
SELECT EmployeeID, [1] AS SM1, [2] AS SM2, [3] AS SM3, [4] AS SM4, [5] AS SM5 FROM (SELECT PurchaseOrderID, EmployeeID, ShipMethodID FROM Purchasing.PurchaseOrderHeader) ORD PIVOT ( COUNT(PurchaseOrderID) FOR ShipMethodID IN([1], [2], [3], [4], [5]) ) AS PVT
以下为结果集:
EmployeeID SM1 SM2 SM3 SM4 SM5 ----------- ----------- ----------- ----------- ----------- ----------- 164 56 62 12 89 141 198 24 27 6 45 58 223 56 67 17 98 162 231 50 67 12 81 150 233 55 62 12 106 125 238 53 58 13 102 134 241 50 59 13 108 130 244 55 47 17 93 148 261 58 54 11 120 117 264 50 58 15 86 151 266 58 68 14 116 144 274 24 26 6 41 63
COUNT(PurchaseOrderID) 函数为列表中的每个托运方法统计行数。请注意,PIVOT 不允许使用 COUNT(*)。列别名用来向结果列提供更具描述性的名称。当您具有较少的托运方法并且它们的 ID 事先已知时,使用 PIVOT 在不同的列中显示每个托运方法的定单计数是合理的。
还可以用从表达式中得到的值为枢轴。例如,假设您希望返回每个定单年中每个雇员的运费总值,并且用年份作为列的枢轴。定单年是从 OrderDate 列中得到的:
SELECT EmployeeID, [2001] AS Y2001, [2002] AS Y2002, [2003] AS Y2003, [2004] AS Y2004 FROM (SELECT EmployeeID, YEAR(OrderDate) AS OrderYear, Freight FROM Purchasing.PurchaseOrderHeader) AS ORD PIVOT ( SUM(Freight) FOR OrderYear IN([2001], [2002], [2003], [2004]) ) AS PVT
以下为结果集:EmployeeID Y2001 Y2002 Y2003 Y2004 ----------- ----------- ----------- ----------- ------------ 164 509.9325 14032.0215 34605.3459 105087.7428 198 NULL 5344.4771 14963.0595 45020.9178 223 365.7019 12496.0776 37489.2896 117599.4156 231 6.8025 9603.0502 37604.3258 75435.8619 233 1467.1388 9590.7355 32988.0643 98603.745 238 17.3345 9745.1001 37836.583 100106.3678 241 221.1825 6865.7299 35559.3883 114430.983 244 5.026 5689.4571 35449.316 74690.3755 261 NULL 10483.27 32854.9343 73992.8431 264 NULL 10337.3207 37170.1957 82406.4474 266 4.2769 9588.8228 38533.9582 115291.2472 274 NULL 1877.2665 13708.9336 41011.3821
交叉分析报表在数据仓库方案中很常见。请考虑下面的 OrdersFact 表(您用 AdventureWorks 中的销售定单和销售定单详细信息数据填充该表):
CREATE TABLE OrdersFact ( OrderID INT NOT NULL, ProductID INT NOT NULL, CustomerID NCHAR(5) NOT NULL, OrderYear INT NOT NULL, OrderMonth INT NOT NULL, OrderDay INT NOT NULL, Quantity INT NOT NULL, PRIMARY KEY(OrderID, ProductID) ) INSERT INTO OrdersFact SELECT O.SalesOrderID, OD.ProductID, O.CustomerID, YEAR(O.OrderDate) AS OrderYear, MONTH(O.OrderDate) AS OrderMonth, DAY(O.OrderDate) AS OrderDay, OD.OrderQty FROM Sales.SalesOrderHeader AS O JOIN Sales.SalesOrderDetail AS OD ON O.SalesOrderID = OD.SalesOrderID
要获得每个年份和月份的总数量,并且在行中返回年份,在列中返回月份,则请使用以下查询:
SELECT * FROM (SELECT OrderYear, OrderMonth, Quantity FROM OrdersFact) AS ORD PIVOT ( SUM(Quantity) FOR OrderMonth IN([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12]) ) AS PVT
以下为结果集:OrderYear 1 2 3 4 5 6 7 8 9 10 11 12 ---------- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- 2001 NULL NULL NULL NULL NULL NULL 966 2209 1658 1403 3132 2480 2002 1040 2303 1841 1467 3179 2418 7755 11325 9066 5584 8268 6672 2003 3532 5431 4132 5694 8278 6444 11288 18986 18681 11607 14771 15855 2004 9227 10999 11






