SQL Server连接表和数据透视表

时间:2013-06-12 18:53:12

标签: sql sql-server-2008 join pivot

我有两个数据表

表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      |

我需要一个会产生

的查询

TAB3

    --------------------------------------------------------------------------------
    | 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

我对转动非常不熟悉,也不确定是否可以使用转轴。

1 个答案:

答案 0 :(得分:43)

这应该有效:

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表上添加条件时,最大的区别就在于它 - 您应该测试并查看哪个查询更好。

但是,我建议您在表示层中进行旋转吗?例如,如果您使用的是SSRS,则很容易使用矩阵控件来完成所有的旋转。这是最好的,因为如果你添加一个新的Category,你将不会修改所有的SQL代码!

有一种方法可以动态查找要转移的列名,但它涉及动态SQL。我不建议这是最好的方式,尽管它是可能的。

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

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