34

我有两个数据表

表格1

    ---------------------------------------------------
    | SALEID | SOLDBY | SALEPRICE | MARGIN |   DATE   |
    |  1     |  'aa'  |  10,000   |   10   | 2013-1-1 |
    |  2     |  'bb'  |  25,000   |    5   | 2013-5-1 |

表 2

    ---------------------------------------------------
    | SALEITEMID | SALEID | SALEPRICE | CATEGORY |
    |  1         |  1     |   6,000   | BOOKS    |
    |  2         |  1     |   4,000   | PRINTING |
    |  3         |  2     |   5,000   | BOOKS    |
    |  4         |  2     |   12,000  | PRINTING |
    |  5         |  2     |   8,000   | DVD      |

我需要一个会产生的查询

选项卡3

    --------------------------------------------------------------------------------
    | SALEID | SOLDBY | SALEPRICE | MARGIN |   DATE   |  BOOKS  | PRINTING | DVD
    |  1     |  'aa'  |  10,000   |   10   | 2013-1-1 |  6,000  |  4,000   | 0
    |  2     |  'bb'  |  25,000   |    5   | 2013-5-1 |  5,000  | 12,000   | 8,000

我对枢轴很陌生,不确定枢轴是否可行。

4

1 回答 1

56

这应该有效:

WITH Sales AS (
   SELECT
      S.SaleID,
      S.SoldBy,
      S.SalePrice,
      S.Margin,
      S.Date,
      I.SalePrice,
      I.Category
   FROM
      dbo.Sale S
      INNER JOIN dbo.SaleItem I
         ON S.SaleID = I.SaleID
)
SELECT *
FROM
   Sales
   PIVOT (Max(SalePrice) FOR Category IN (Books, Printing, DVD)) P
;

或者:

SELECT
   S.SaleID,
   S.SoldBy,
   S.SalePrice,
   S.Margin,
   S.Date,
   I.Books,
   I.Printing,
   I.DVD
FROM
   dbo.Sale S
   INNER JOIN (
      SELECT *
      FROM
         (SELECT SaleID, SalePrice, Category FROM dbo.SaleItem) I
         PIVOT (Max(SalePrice) FOR Category IN (Books, Printing, DVD)) P
   ) I ON S.SaleID = I.SaleID
;

这些具有相同的结果集,实际上可能被查询优化器视为相同,但可能不是。当您开始将条件放在表上时,最大的区别就开始发挥作用了Sale——您应该测试并查看哪个查询效果更好。

PIVOT注意:在使用时,只有应该作为结果输出的一部分的列才可用,这一点至关重要。这就是为什么上述两个查询有额外的派生表子查询(SELECT ...),以便只公开特定的列。PIVOT未在枢轴表达式中列出的所有可供查看的列将隐式分组并包含在最终输出中。这可能不是您想要的。

但是,我可以建议您在表示层中进行旋转吗?例如,如果您使用的是 SSRS,那么使用矩阵控件非常容易,它会为您完成所有旋转。那是最好的,因为如果你添加一个新的Category,你就不需要修改你所有的 SQL 代码了!

有一种方法可以动态查找要透视的列名,但它涉及动态 SQL。我也不建议将其作为最好的方法,尽管这是可能的。

另一种可行方法是预处理这个查询——意思是在Category表上设置一个触发器,重写一个视图以包含所有现存的类别。这确实解决了我提到的许多其他问题,但同样,使用表示层是最好的。

注意:如果您的列名(以前是值)有空格、是数字或以数字开头,或者不是有效的标识符,则必须用方括号将它们括起来,如PIVOT (Max(Value) FOR CategoryId IN ([1], [2], [3], [4])) P. 或者,您可以在值到达查询部分之前修改值PIVOT以添加一些字母或删除空格,这样列列表就不需要转义。要进一步阅读此内容,请查看SQL Server中标识符的规则。

于 2013-06-12T18:56:57.843 回答