假设您希望呈现 ItemAttributes 表中的数据,该表具有与每个油画项目(项目 5 、6 )相对应的行以及与每个属性相对应的列。如果没有 PIVOT 运算符,则必须编写如下所示的查询:
SELECT itemid, MAX(CASE WHEN attribute = 'artist' THEN value END) AS [artist], MAX(CASE WHEN attribute = 'name' THEN value END) AS [name], MAX(CASE WHEN attribute = 'type' THEN value END) AS [type], MAX(CASE WHEN attribute = 'height' THEN value END) AS [height], MAX(CASE WHEN attribute = 'width' THEN value END) AS [width] FROM ItemAttributes AS ATR WHERE itemid IN(5,6) GROUP BY itemid
以下为结果集:itemid artist name type height width ------ ---------------- ---------------- ---------- ------ ------ 5 Claude Monet Field of Poppies Oil 19.625 25.625 6 Vincent Van Gogh The Starry Night Oil 28.750 36.250
PIVOT 运算符使您可以维护更简短且更可读的代码以获得相同的结果:
SELECT * FROM ItemAttributes AS ATR PIVOT ( MAX(value) FOR attribute IN([artist], [name], [type], [height], [width]) ) AS PVT WHERE itemid IN(5,6)
像大多数新功能一样,对 PIVOT 运算符的理解来自于试验和使用。PIVOT 语法中的某些元素是显而易见的,并且只需要您弄清楚这些元素与不使用新运算符的查询之间的关系。其他元素则是隐藏的。
您可能会发现下列术语能够帮助您理解 PIVOT 运算符的语义:
table_expression
PIVOT 运算符所作用于的虚拟表(查询中位于 FROM 子句和 PIVOT 运算符之间的部分):在该示例中为 ItemAttributes AS ATR 。
pivot_column
table_expression 中您希望将其值旋转为结果列的列:在该示例中为 attribute 。
column_list
pivot_column 中您希望将其呈现为结果列的值列表(在 IN 子句前面的括号中)。它们必须表示为合法的标识符:在该示例中为 [artist]
、[name]
、[type] 、[height] 、[width] 。
aggregate_function
用于生成结果中的数据或列值的聚合函数:在该示例中为 MAX() 。
value_column
table_expression 中的用作 aggregate_function 的参数的列:在该示例中为 value 。
group_by_list
隐藏的部分 — table_expression 中除 pivot_column 和 value_column 以外所有用来对结果进行分组的列:在该示例中为 itemid 。
select_list
SELECT 子句后面的列列表,可能包括 group_by_list 和 column_list 中的任何列。别名可以用来更改结果列的名称:* 在该示例中,返回 group_by_list 和 column_list 中的所有列。
PIVOT 运算符为 group_by_list 中的每个唯一值返回一个行,就好像您的查询带有 GROUP BY 子句并且您指定了这些列一样。请注意,group_by_list 是隐含的;它没有在查询中的任何位置显式指定。它包含 table_expression 中除 pivot_column 和 value_column 以外的所有列。理解这一点可能是理解您用 PIVOT 运算符编写的查询按照它们本身的方式工作以及在某些情况下可能获得错误的原因的关键。
可能的结果列包括 group_by_list 和 中的值。如果您指定星号 (*),则查询会返回这两个列表。结果列的数据部分或结果列值是通过将 value_column 用作参数的 aggregate_function 计算的。
下面的用各种颜色突出显示的代码说明了使用 PIVOT 运算符的查询中的不同元素:
SELECT * -- itemid, [artist], [name], [type], [height], [width] FROM ItemAttributes AS ATR PIVOT ( MAX(value) FOR attribute IN([artist], [name], [type], [height], [width]) ) AS PVT WHERE itemid IN(5,6)
以下代码将不同的元素与不使用 PIVOT 运算符的查询相关联:
SELECT itemid, MAX(CASE WHEN attribute = 'artist' THEN value END) AS [artist], MAX(CASE WHEN attribute = 'name' THEN value END) AS [name], MAX(CASE WHEN attribute = 'type' THEN value END) AS [type], MAX(CASE WHEN attribute = 'height' THEN value END) AS [height], MAX(CASE WHEN attribute = 'width' THEN value END) AS [width] FROM ItemAttributes AS ATR WHERE itemid IN(5,6) GROUP BY itemid
请注意,您必须显式指定 中的值。PIVOT 运算符没有提供在静态查询中从 pivot_column 动态得到这些值的选项。您可以使用动态 SQL 自行构建查询字符串以达到该目的。
将上一个 PIVOT 查询向前推进一步,假设您希望为每个拍卖项目返回所有与油画相关的属性。您希望包括那些出现在 AuctionItems 中的属性以及那些出现在 ItemAttributes 中的属性。您可能尝试以下查询,它会返回错误:
SELECT * FROM AuctionItems AS ITM JOIN ItemAttributes AS ATR ON ITM.itemid = ATR.itemid PIVOT ( MAX(value) FOR attribute IN([artist], [name], [type], [height], [width]) ) AS PVT WHERE itemtype = 'Painting'
以下为错误消息:.Net SqlClient Data Provider:Msg 8156, Level 16, State 1, Line 1 The column 'itemid' was specified multiple times for 'PVT'.
请记住,PIVOT 作用于 table_expression,它是由该查询中 FROM 子句和 PIVOT 子句之间的部分返回的虚拟表。在该查询中,虚拟表包含 itemid 列的两个实例 — 一个源自 AuctionItems ,另一个源自 ItemAttributes 。您可能会试探按如下方式修改该查询,但是您仍将获得错误:
SELECT ITM.itemid, itemtype, whenmade, initialprice, [artist], [name], [type], [height], [width] FROM AuctionItems AS ITM JOIN ItemAttributes AS ATR ON ITM.itemid = ATR.itemid PIVOT ( MAX(value) FOR attribute IN([artist], [name], [type], [height], [width]) ) AS PVT WHERE itemtype = 'Painting'
以下为错误消息:.Net SqlClient Data Provider: Msg 8156, Level 16, State 1, Line 1 The column 'itemid' was specified multiple times for 'PVT'. .Net SqlClient Data Provider: Msg 107, Level 15, State 1, Line 1 The column prefix 'ITM' does not match with a table name or alias name used i






