SQL连接没有给我正确的总数

时间:2019-07-12 13:49:13

标签: sql sql-server stored-procedures

我正在尝试从多个交易表中获取数字报告。每个表都有一个外键,该外键用于查询使用该日期的日期以及在Site_Lookup_Id处的位置。它给我的数字比实际值要大得多。

@Site_Lookup_Ids dbo.Id_List READONLY

SELECT SL.Site_Lookup_Id, D.[Start],SUM(I.Amount) AS Income, 
       SUM(P.Amount) AS Payouts,SUM(DP.Amount) AS Deposit 
FROM CashUp_Site_Lookup SL
INNER JOIN @Site_Lookup_Ids IDs ON Ids.Id = SL.Site_Lookup_Id
INNER JOIN CashUp_Day D ON SL.Day_Id = D.Day_Id
LEFT JOIN CashUp_Deposit DP ON DP.Redeemed_Site_Lookup_Id = SL.Site_Lookup_Id 
                            AND DP.No_Show != 1
LEFT JOIN CashUp_Income I ON I.Site_Lookup_Id = SL.Site_Lookup_Id
LEFT JOIN CashUp_Payout P ON P.Site_Lookup_Id = SL.Site_Lookup_Id
GROUP BY SL.Site_Lookup_Id, D.[Start]

并非所有的总和都将具有值,因为某些天当天将不进行给定表的任何交易-在此值应为零。

问题是,执行此操作给我带来了疯狂的高价值-一天的收入为7500英镑,而如果我进行简单的检查,则一天的收入为40英镑。

SELECT SUM(Amount) FROM Cashup_Income WHERE Site_Lookup_Id IN (values...)

2 个答案:

答案 0 :(得分:1)

也许像...

这实际上取决于关系以及何时希望对值求和。

SELECT SL.Site_Lookup_Id
     , D.[Start]
     , SUM(I.Amount) over (partition by Key of I table) AS Income
     , SUM(P.Amount) over (partition by Key of P table) AS Payouts
     , SUM(DP.Amount) over (partition by Key of DP Table) AS Deposit 
FROM CashUp_Site_Lookup SL
INNER JOIN @Site_Lookup_Ids IDs ON Ids.Id = SL.Site_Lookup_Id
INNER JOIN CashUp_Day D ON SL.Day_Id = D.Day_Id
LEFT JOIN CashUp_Deposit DP ON DP.Redeemed_Site_Lookup_Id = SL.Site_Lookup_Id 
                            AND DP.No_Show != 1
LEFT JOIN CashUp_Income I ON I.Site_Lookup_Id = SL.Site_Lookup_Id
LEFT JOIN CashUp_Payout P ON P.Site_Lookup_Id = SL.Site_Lookup_Id
GROUP BY SL.Site_Lookup_Id, D.[Start]

问题源于您的表为1:M的事实,导致值重复。然后将这些重复的值添加到您的总和中。联接导致此问题。因此,我认为您可以使用分区求和以消除重复项,或者:

使用派生表或CTE并在加入之前对值求和。

使用CTE(公用表表达式)

WITH DP AS (SELECT sum(Amount) As Deposit 
                 , Redeemed_Site_Lookup_ID
            FROM CashUp_Deposit
            WHERE No_Show !=1
            GROUP BY Redeemed_Site_Lookup_ID),
     I  AS (SELECT sum(Amount) as Income
                 , Site_Lookup_Id 
            FROM CashUp_Income 
            GROUP BY Site_Lookup_Id),
     P AS (SELECT sum(Amount) as Payouts
                 , Site_Lookup_Id 
            FROM CashUp_Payout 
            GROUP BY Site_Lookup_Id)

SELECT SL.Site_Lookup_Id
     , D.[Start]
     , Income
     , Payouts
     , Deposit 
FROM CashUp_Site_Lookup SL
INNER JOIN @Site_Lookup_Ids IDs 
        ON Ids.Id = SL.Site_Lookup_Id
INNER JOIN CashUp_Day D 
        ON SL.Day_Id = D.Day_Id
LEFT JOIN DP 
       ON DP.Redeemed_Site_Lookup_Id = SL.Site_Lookup_Id 
LEFT JOIN I 
       ON I.Site_Lookup_Id = SL.Site_Lookup_Id
LEFT JOIN P 
       ON P.Site_Lookup_Id = SL.Site_Lookup_Id

答案 1 :(得分:1)

大概是通过联接生成笛卡尔乘积。由于您没有过滤条件,因此请在join之前 进行聚合:

LEFT JOIN
(SELECT DP.Redeemed_Site_Lookup_Id, SUM(DP.Amount) AS Deposit 
 FROM CashUp_Deposit DP
 WHERE DP.No_Show != 1
 GROUP BY DP.Redeemed_Site_Lookup_Id
) DP
ON DP.Redeemed_Site_Lookup_Id = SL.Site_Lookup_Id LEFT JOIN
(SELECT I.Site_Lookup_Id, SUM(I.Amount) AS Income
 FROM CashUp_Income I
 GROUP BY I.Site_Lookup_Id
) I
ON I.Site_Lookup_Id = SL.Site_Lookup_Id LEFT JOIN
(SELECT P.Site_Lookup_Id, SUM(P.Amount) AS Payout
 FROM CashUp_Payout P
 GROUP BY I.Site_Lookup_Id
) P
ON P.Site_Lookup_Id = SL.Site_Lookup_Id 

然后调整查询的其余部分以删除GROUP BYSUM()