【问题标题】:Duplication involving SUM, LEFT JOIN and GROUP BY涉及 SUM、LEFT JOIN 和 GROUP BY 的重复
【发布时间】:2013-09-28 13:15:12
【问题描述】:

我遇到了一个涉及 SUM、LEFT OUTER JOIN 和 GROUP BY 命令的问题,但不知道我的错误在哪里。

我有两张表,一张用于客户交易,一张用于客户索赔。一个客户可以有多个交易和多个索赔,但在两个表中,行都是唯一的。客户也可以没有索赔。

交易表示例:

Transactions:
Customer | Transaction Year | Amount
-------------------------------------
A        | 2007             | 100
A        | 2008             | 80
A        | 2008             | 50
A        | 2009             | 210

声明表示例:

Claims:
Customer | Claim Year | Amount
-------------------------------
A        | 2007       | 30
A        | 2007       | 40
A        | 2009       | 110

所需的输出是将两个金额相加,并为 Customer 和 Year 的每个唯一组合生成一行。

Desired Output:
Customer | Year | Transaction Amount | Claim Amount
----------------------------------------------------
A        | 2007 | 100                | 70
A        | 2008 | 130                | NULL
A        | 2009 | 210                | 110

我使用 LEFT OUTER JOIN 命令和 GROUP BY 命令来获取 Customer 和 Year 值。但我得到的是交易金额值的重复,并且倍数与索赔表中匹配的行数有关。

所以使用我的示例数据,我得到以下信息:

Actual Output:
Customer | Year | Transaction Amount | Claim Amount
----------------------------------------------------
A        | 2007 | 200                | 70
A        | 2008 | 130                | NULL
A        | 2009 | 210                | 110

在 2007 年,有两个索赔导致 Transactions.Amount 值乘以 2(当有 3 个索赔时,Transaction.Amount 增加三倍,等等)。

我的代码如下:

SELECT Transactions.Customer,
   Transactions.Year,
   sum(Transactions.Transaction Amount),
   sum(Claims.Claim Amount)
FROM Transactions
   LEFT JOIN Claims ON Claims.Customer = Transactions.Customer
      AND Transactions.Year = Claims.Year
GROUP BY Transactions.Customer, Transactions.Year

答案是否存在于子查询中?我对它们不熟悉,所以任何指针都会很棒。谢谢。

【问题讨论】:

  • 你能试着写一个不同的子句吗?
  • DISTINCT 不会改变结果,因为它适用于结果表的行(现在是不同的),而不是列。

标签: mysql sql


【解决方案1】:

因此,查看发生情况的第一步是删除 SUM,然后选择交易金额和索赔金额。这样您就可以看到正在返回的数据。您会看到 A/2007 上的连接将有两倍的交易金额,因为它将每一行连接到索赔表。

一种解决方案是使用子查询,如您所说,在加入之前分别进行 SUM。

SELECT 
   Transactions.Customer,
   Transactions.Year,
   SumTransaction,
   SumClaim
FROM (
      select Customer, Year, sum(Transaction Amount) SumTransaction 
      from Transactions
      group by Customer, Year
   ) Transactions
   LEFT JOIN (
      select Customer, Year, sum(Claim Amount) sumClaim 
      from Claims
      group by Customer, Year
   ) Claims
   ON Claims.Customer = Transactions.Customer
      AND Transactions.Year = Claims.Year

考虑到您的限制,另一种可能的解决方案:

SELECT 
   Transactions.Customer,
   Transactions.Year,
   SUM(Transaction Amount),
   (SELECT SUM(Claim Amount) from Claims where Claims.Customer = Transactions.Customer and Claims.Year = Transactions.Year)
FROM 
   Transactions
GROUP BY
   Customer, Year

第三种可能的解决方案!!这个不需要任何子查询!看到这个SQL Fiddle

select
    t.Customer,
    t.Year,
    sum(distinct t.Amount),
    sum(c.Amount)
from
    Transactions t
    left join Claims c
        on  t.Customer = c.Customer
            and t.Year = c.year
group by
    t.Customer,
    t.Year

【讨论】:

  • 您在子查询中忘记group by
  • 要查看发生了什么,我还必须删除 GROUP BY 语句。您的解决方案可能有效......如果我不受我的应用程序的限制。我正在使用 Zoho Reports,它目前不支持 FROM 子句中的 SELECT 查询 - 烦人。对于不使用子查询的解决方案有什么想法吗?
  • 您可以在选择列表中使用子查询吗?请参阅上面的编辑以获取可能的解决方案...
  • 我实际上只是测试了另一个不需要子查询的解决方案!请参阅编辑/SQL Fiddle :)
  • 第二个解决方案不起作用 - 它被用作列标题(我有逗号!)...尝试第三个...
【解决方案2】:
With T as (
    SELECT  Customer,
            [Transaction Year],
            sum(Amount) AS TransactionAmount
    FROM Transactions
    GROUP BY Customer, [Transaction Year]
), C AS 
    SELECT  Customer,
            [Claim Year],
            sum(Amount) as ClaimAmount
    FROM Claims
    GROUP BY Customer, [Claim Year]
)
SELECT  T.Customer,
        [Transactions Year],
        TransactionAmount,
        ClaimAmount
FROM    T
   LEFT JOIN C ON C.Customer = T.Customer
      AND [Transactions Year] = [Claim Year]

【讨论】:

  • 这被标记为 MySql,它没有 CTE 功能。
  • 谢谢,没意识到。
【解决方案3】:

由于您有两个索赔,查询将计算 2007 年的交易金额两次,因此交易金额将被计算两次。

即正在使用的返回数据是:

Customer | Transaction Year | Transaction Amount | Claim Amount
----------------------------------------------------------------
A        | 2007             | 100                | 30
A        | 2007             | 100                | 40
A        | 2008             | 80                 |
A        | 2008             | 50                 |
A        | 2009             | 210                | 110

类似下面的东西,虽然不是很漂亮,但应该可以解决问题:

SELECT 
   t.Customer
   ,t.Year
   ,[Transaction Amount] = SUM(t.[Transaction Amount])
   ,[Claim Amount] = c.[Claim Amount]
FROM 
    Transactions t
    LEFT JOIN (
        SELECT 
            Customer
            ,Year
            ,SUM([Claim Amount])
        FROM
           Claims
        GROUP BY
           Customer, Year
    ) c ON c.Customer = t.Customer c.Year = t.Year
GROUP BY t.Customer, t.Year, c.[Claim Amount]

【讨论】:

    猜你喜欢
    • 2021-01-30
    • 2015-08-21
    • 1970-01-01
    • 1970-01-01
    • 2016-04-11
    • 1970-01-01
    • 1970-01-01
    • 2020-05-17
    • 1970-01-01
    相关资源
    最近更新 更多