SQL Server 连接表和数据透视表

Posted

技术标签:

【中文标题】SQL Server 连接表和数据透视表【英文标题】:SQL server join tables and pivot 【发布时间】:2013-06-09 00:23:11 【问题描述】:

我有两张数据表

表 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

我对枢轴很陌生,不确定枢轴是否适合。

【问题讨论】:

有多少个类别?这是完整列表吗?未来还会有更多吗? 大约有7个类别。不会超过它。 【参考方案1】:

这应该可行:

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 可以看到的所有未在数据透视表达式中列出的列将被隐式分组并包含在最终输出中。这可能不是您想要的。

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

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

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

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

【讨论】:

谢谢 真的很有帮助 ....第一个查询有效,在 forst 查询中请在 INNER JOIN dbo.SaleItem 或 INNER JOIN dbo.SaleItem 后添加“我”谢谢 确保检查Max() 是否合适——如果每个SaleID + Category 可能有多个,则可能需要Sum(),或者某种Row_Number() 预计算,因此值可以在不同的行上。

以上是关于SQL Server 连接表和数据透视表的主要内容,如果未能解决你的问题,请参考以下文章

Microsoft Access 数据透视表到 SQL Server 数据透视表

在 SQL Server 中使用数据透视表作为视图

“常规”数据透视表和 olap 类型数据透视表之间的区别

laravel 使用 in 子句模型名称连接多态数据透视表

SQL Server 2016 中的数据透视表

具有多索引的 Pandas 子数据透视表和总数据透视表