【问题标题】:How to use SQL math functions with multiple joins如何使用具有多个连接的 SQL 数学函数
【发布时间】:2020-08-10 19:20:01
【问题描述】:

在 SQL Server 中,我有两个事实表。 FactA 我将使用 COUNT(DISTINCT) 并且需要使用两个连接来从 DimB 获取所需的 GROUP BY 和 WHERE 数据。 FactB 使用 SUM 并且只需要一个连接到 DimB。现在我可以让这些查询一个一个地工作,但我完全迷失了,试图将它们合并到一个查询中。

这是一个极其简化的示例数据:

    CREATE TABLE FactA
    ([Customer] varchar(3), [Dept] varchar(5))
;
    
INSERT INTO FactA
    ([Customer], [Dept])
VALUES
    ('Aaa', 'DeptA'),
    ('Bbb', 'DeptA'),
    ('Ccc', 'DeptA'),
    ('Ddd', 'DeptB'),
    ('Fff', 'DeptB'),
    ('Aaa', 'DeptC'),
    ('Aaa', 'DeptC')
;

CREATE TABLE DimA
    ([Dept] varchar(5), [Area] varchar(2))
;
    
INSERT INTO DimA
    ([Dept], [Area])
VALUES
    ('DeptA', 'SW'),
    ('DeptB', 'NW'),
    ('DeptC', 'SE')
;


CREATE TABLE DimB
    ([Area] varchar(2), [Code] varchar(2), [PO] varchar(2))
;
    
INSERT INTO DimB
    ([Area], [Code], [PO])
VALUES
    ('SW', 'XA', 'Z1'),
    ('NW', 'XB', 'Z3'),
    ('SE', 'XC', 'Z5')
;


CREATE TABLE FactB
    ([Sales] int, [Code] VARCHAR(2))
;
    
INSERT INTO FactB
    ([Sales], [Code])
VALUES
    (20, 'XA'),
    (10, 'XA'),
    (25, 'XA'),
    (30, 'XB'),
    (40, 'XB'),
    (15, 'XC'),
    (20, 'XC'),
    (35, 'XC')
;

自行工作并给出预期结果的示例查询是:

SELECT DimB.PO,COUNT(DISTINCT FactA.Customer) As Customers
FROM FactA
JOIN DimA ON DimA.Dept = FactA.Dept
Join DimB ON DimB.Area = DimA.Area
GROUP BY DimB.PO

SELECT DimB.PO, sum(FactB.Sales) As TotalSales
FROM FactB
JOIN DimB ON DimB.Code = FactB.Code
GROUP BY DimB.PO

我需要将这两者结合起来,这样我就可以通过一个查询得到结果,并使用 DimB 中的 GROUP BY 和 WHERE 子句。我试过这个:

SELECT DimB.PO,COUNT(DISTINCT FactA.Customer) As Customers, SUM(FactB.Sales) As TotalSales
FROM FactA
JOIN DimA ON DimA.Dept = FactA.Dept
Join DimB ON DimB.Area = DimA.Area
Join FactB ON FactB.Code = DimB.Code
GROUP BY DimB.PO

它惨遭失败,因为它在 TotalSales 中让位于太多的数字。我相信这是太多的销售额,因为有很多加入。搜索我相信子查询可能是答案,但我对我应该对哪一部分进行子查询感到不知所措。非常感谢任何有时间提供帮助的人。

【问题讨论】:

  • 您期望从“组合”查询中得到什么结果?这对我们来说并不明显,因为您的单独查询按 DimB.PO 分组,但您的组合查询却试图按 DimB.Code 分组。
  • 抱歉,我编辑了“组合”查询以使用 DimB.PO,因为能够使用 DimB-table 进行分组或 where 子句非常重要。
  • 抛开错字,向我们展示您期望的结果对您仍然有用。

标签: sql sql-server


【解决方案1】:

我要猜这些是你想要的结果。请始终明确说明所需的结果,这样我们就不必猜测了。

;WITH SalesByCode(Code, Sales) AS 
(
  SELECT Code, SUM(Sales) FROM dbo.FactB GROUP BY Code
)
SELECT DimB.PO, 
  Customers  = COUNT(DISTINCT FactA.Customer), 
  TotalSales = MAX(sbc.Sales)
FROM dbo.FactA
JOIN dbo.DimA ON DimA.Dept = FactA.Dept
Join dbo.DimB ON DimB.Area = DimA.Area
Join SalesByCode AS sbc ON DimB.Code = sbc.Code
GROUP BY DimB.PO;

结果:

PO      Customers    TotalSales 
----    ---------    ----------
Z1              3            55
Z3              2            70
Z5              1            70

【讨论】:

  • 你说得对,这正是我所需要的,下次我会努力说得更清楚!我将此答案标记为正确,因为我认为这是解决问题的最简单方法。感谢您的时间和帮助。其他人的答案也很好,非常感谢其他人!
【解决方案2】:

以下应该有效:

SELECT
   DimB.PO
  ,sub.CustomerCount
  ,sum(FactB.Sales)  TotalSales
 from FactB
  inner join DimB
   on FactB.Code = DimB.Code
  inner join (--  Get the distinct list of Customers for each Area)
              select
                 DimA.Area
                ,count(distinct FactA.Customer)  CustomerCount
               from DimA
                inner join FactA
                 on FactA.Dept = DimA.Dept
               group by
                DimA.Area)  sub
   on sub.Area = DimB.Area
 group by
   DimB.PO
  ,sub.CustomerCount

这允许具有相同区域的不同采购订单(因此,相同的客户数量)。

【讨论】:

    【解决方案3】:

    如果您想对 DimB 表中的所有 PO 进行计数和总和,即使它们是 0,那么您应该从 DimB 表开始,然后加入子查询。

    SELECT DimB.PO, 
           ISNULL(a.Customers, 0) AS Customers,
           ISNULL(b.TotalSales, 0) AS TotalSales
    FROM DimB
    LEFT JOIN (
       SELECT DimB.PO,COUNT(DISTINCT FactA.Customer) As Customers
       FROM FactA
       JOIN DimA ON DimA.Dept = FactA.Dept
       Join DimB ON DimB.Area = DimA.Area
       GROUP BY DimB.PO
    ) AS a ON a.PO = DimB.PO
    LEFT JOIN (
       SELECT DimB.PO, sum(FactB.Sales) As TotalSales
       FROM FactB
       JOIN DimB ON DimB.Code = FactB.Code
       GROUP BY DimB.PO
    ) AS b ON b.PO = DimB.PO
    
    

    【讨论】:

      【解决方案4】:

      您可以使用CTE并加入他们,请参考下面

          WITH CUSTOMERS
      AS (
          SELECT DimB.PO
              ,COUNT(DISTINCT FactA.Customer) AS Customers
          FROM FactA
          JOIN DimA ON DimA.Dept = FactA.Dept
          JOIN DimB ON DimB.Area = DimA.Area
          GROUP BY DimB.PO
          )
          ,SALES
      AS (
          SELECT DimB.PO
              ,sum(FactB.Sales) AS TotalSales
          FROM FactB
          JOIN DimB ON DimB.Code = FactB.Code
          GROUP BY DimB.PO
          )
      SELECT CUSTOMERS.PO, CUSTOMERS.Customers, SALES.TotalSales
      FROM CUSTOMERS
      JOIN SALES ON CUSTOMERS.PO = SALES.PO
      

      【讨论】:

        【解决方案5】:
        select TEMP.*, sum(FactB.Sales) As TotalSales
        from (QUERY 1) as TEMP
        JOIN DimB on DimB.PO= TEMP.PO
        JOIN FactB ON DimB.Code = FactB.Code
        GROUP BY DimB.PO
        

        【讨论】:

        • 恐怕我不明白我应该写什么(QUERY 1)。但是其他答案确实解决了我的问题,所以如果你真的不喜欢它,就不需要进一步解释。
        • Query 1 是你写的第一个 select 语句
        【解决方案6】:

        我假设,当您使用 Fact 和 Dimension 等术语时,这意味着是 Kimball 维度数据模型?如果是这种情况,那么我认为您正在努力编写查询以提供所需结果的原因是您的数据模型设计不正确 - 因为设计 Kimball 数据模型的主要目的之一是进行分析查询很容易,如果您发现构建所需的查询很困难,那么根本问题通常在于数据模型。

        在您的示例中,FactA 没有度量(尽管我猜它可能故意是一个无事实的事实表?)。

        您正在将维度相互连接,这是不正确的,维度应始终通过事实表相互关联。

        如果您想组合来自多个事实表的度量,您应该独立查询每个事实表,然后使用通用的一致维度合并结果。

        【讨论】:

        • 这实际上只是一个运行在 SQL Server 上的生产数据库。我重命名了表格并删除了许多不必要的列。我只是习惯于命名事实和维度:-)
        猜你喜欢
        • 2014-09-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-10-27
        相关资源
        最近更新 更多