带有两个LEFT JOIN的SUM问题

时间:2015-01-13 00:01:46

标签: sql sql-server join left-join

在下面的查询中,当我有两个左连接时,我遇到了麻烦。会发生什么是两个左连接的总和不正确(提升)。当我删除第二个左连接时,查询正确运行。如何使用第二个左连接运行此查询?

SELECT o.IdNoLocation,
COUNT(DISTINCT o.EncodedId) AS "Frequency", 
ISNULL(SUM(o.Subtotal), 0) AS "Spend", 
ISNULL(SUM(os.Amount), 0) AS "Surcharges",
ISNULL(SUM(od.Amount), 0) AS "Discounts" 
FROM ((tblOrder o
LEFT JOIN tblOrderSurcharge os ON o.OrderId=os.OrderId) 
LEFT JOIN tblOrderDiscount od ON o.OrderId=od.OrderId)
WHERE 
o.BusinessDate BETWEEN '2014-01-01' AND '2014-12-31'
AND o.IdNoLocation <> 'X'
GROUP BY o.IdNoLocation

2 个答案:

答案 0 :(得分:0)

tblOrderSurchargetblOrderDiscount中有多个相关行时,这是预期的结果...您在这两个表的行之间有一个隐式的半交叉连接。

如果你需要在一个声明中返回的总数,有几种“修复”这种方法。

一种选择是使用内联视图执行总计,然后组合行。实质上,运行单独的查询以从每个表中获取总计,然后将结果组合在唯一键上。例如:

SELECT o.IdNoLocation
     , o.Frequency
     , ISNULL(o.Spend, 0)       AS Spend
     , ISNULL(s.Surcharges), 0) AS Surcharges
     , ISNULL(s.Discounts), 0)  AS Discounts
  FROM ( SELECT ooo.IdNoLocation
              , COUNT(DISTINCT ooo.EncodedId) AS Frequency
              , SUM(ooo.Subtotal) AS Spend
           FROM tblOrder ooo
          WHERE ooo.BusinessDate BETWEEN '2014-01-01' AND '2014-12-31'
            AND ooo.IdNoLocation <> 'X'
         GROUP BY ooo.IdNoLocation
       ) o
  LEFT
  JOIN ( SELECT oso.IdNoLocation
              , SUM(oss.Amount) AS Surcharges
           FROM tblOrderSurcharge oss
           JOIN tblOrder oso
             ON oso.OrderId = oss.OrderId
          WHERE oso.BusinessDate BETWEEN '2014-01-01' AND '2014-12-31'
            AND oso.IdNoLocation <> 'X'
          GROUP BY oso.IdNoLocation
       ) s
    ON s.IdNoLocation = o.IdNoLocation
  LEFT
  JOIN ( SELECT odo.IdNoLocation
              , SUM(odd.Amount) AS Discounts
           FROM tblOrderDiscount odd
           JOIN tblOrder odo
             ON odo.OrderId = odd.OrderId
          WHERE odo.BusinessDate BETWEEN '2014-01-01' AND '2014-12-31'
            AND odo.IdNoLocation <> 'X'
          GROUP BY odo.IdNoLocation
       ) d
    ON d.IdNoLocation = o.IdNoLocation

(这不经过测试,只需检查桌面。运行每个内联视图查询(o,s,d)并验证每个查询的结果是否符合预期。然后,运行整个查询,合并行...在外部查询中,我们将执行“外部”连接并处理“缺失”行并用零替换NULL)

另一种选择是在SELECT列表中使用相关子查询。

答案 1 :(得分:0)

要了解为什么这不起作用,请运行此查询:

SELECT o.IdNoLocation,
o.EncodedId AS "Frequency", 
o.Subtotal AS "Spend", 
os.Amount AS "Surcharges",
od.Amount AS "Discounts" 
FROM ((tblOrder o
LEFT JOIN tblOrderSurcharge os ON o.OrderId=os.OrderId) 
LEFT JOIN tblOrderDiscount od ON o.OrderId=od.OrderId)
WHERE 
o.BusinessDate BETWEEN '2014-01-01' AND '2014-12-31'
AND o.IdNoLocation <> 'X'

&#39;正确&#39;答案是使用一张表来收取附加费和折扣。我认为这不再是一个选项,但你可以使用在两个表之间执行UNION ALL的视图来伪造它。