SQL Sum与非唯一日期

时间:2013-11-24 23:38:04

标签: sql

我正在尝试编写一个SQL查询,该查询将总结以下两个示例表中的总产量:

Table: CaseLots
DateProduced        kgProduced
October 1, 2013     10000
October 1, 2013     10000
October 2, 2013     10000

Table: Budget
OperatingDate       BudgetHours
October 1, 2013     24
October 2, 2013     24

我想输出一个表格如下:

TotalProduction   TotalBudgetHours    
30000                   48

到目前为止,我的代码是:

SELECT 
Sum(kgProduced) AS TotalProduction, Sum(BudgetHours) AS TotalBudgetHours
FROM 
dbo.CaseLots INNER JOIN dbo.Budget ON dbo.CaseLots.DateProduced = dbo.Budget.OperatingDate
WHERE 
dbo.Budget.OperatingDate BETWEEN '2013-10-01' AND '2013-10-02'

在一天中生成多个案例批次的情况下,查询似乎是对预算小时的双重总结。我得到的表格如下:

Total Production     BudgetHours
30000                72

我该如何解决这个问题?

5 个答案:

答案 0 :(得分:1)

想想INNER JOIN正在做什么。

对于CaseLot中的每一行,它会在Budget中查找具有匹配日期的任何行。

如果您要在SQL中删除聚合语句,只显示内部联接,您将看到以下结果集:

DateProduced kgProduced OperatingDate BudgetHours

2013年10月1日10000 10月1日,2013 24

2013年10月1日10000 10月1日,2013 24

2013年10月2日10000 10月2日,2013 24

(该死的StackOverflow,为什么你没有表格的Markdown :()

在此基础上运行聚合,很容易看出你的结果是如何获得72小时的。

正确的查询需要首先聚合CaseLots表,然后加入Budget表。

SELECT DateProduced, TotalKgProduced, SUM(BudgetHours) AS TotalBudgetHours
FROM
(
    SELECT DateProduced, SUM(kgProduced) AS TotalKgProduced
    FROM CaseLots
    GROUP BY DateProduced
) AS TotalKgProducedByDay
INNER JOIN
Budget
ON TotalKgProducedByDay.DateProduced = Budget.OperatingDate
WHERE DateProduced BETWEEN '1 Oct 2013' AND '2 Oct 2013'
GROUP BY DateProduced

答案 1 :(得分:1)

问题在INNER JOIN生成一个3行表,因为密钥匹配所有。所以有三个'24',总和为72。

要解决此问题,将其拆分为两个查询可能会更容易。

SELECT Sum(kgProduced) AS TotalProduction
FROM dbo.CaseLots
WHERE dbo.CaseLots.OperatingDate BETWEEN '2013-10-01' AND '2013-10-02'

LEFT JOIN

SELECT Sum(BudgetHours) AS TotalBudgetHours
FROM dbo.Budget
WHERE dbo.Budget.OperatingDate BETWEEN '2013-10-01' AND '2013-10-02'

答案 2 :(得分:0)

这可以通过以下方式轻松实现:

SELECT
   (SELECT SUM(kgProduced) FROM dbo.CaseLots WHERE DateProduced BETWEEN '2013-10-01' AND '2013-10-02') AS TotalProduction,
   (SELECT SUM(BudgetHours) FROM dbo.Budget WHERE OperatingDate BETWEEN '2013-10-01' AND '2013-10-02') AS TotalBudgetHours

没有必要加入这两个表格。

答案 3 :(得分:0)

试试这个:

select DateProduced,TotalProduction,TotalBudgetHours from
  (select DateProduced,sum(kgProduced) as TotalProduction 
  from CaseLots group by DateProduced) p
  join
  (select OperatingDate,sum(BudgetHours) as TotalBudgetHours 
  from Budget group by OperatingDate) b
  on (p.DateProduced=b.OperatingDate)
where p.DateProduced between '2013-10-01' AND '2013-10-02'

答案 4 :(得分:0)

对于这种特殊情况,其他答案更简单。但是,如果SUM表上需要CaseLots 10个不同的值,则需要10个不同的子查询。以下是一个通用的,更具可扩展性的解决方案:

SELECT 
    SUM(DayKgProduced) AS TotalProduction, 
    SUM(BudgetHours) AS TotalBudgetHours
FROM (
    SELECT 
        DateProduced,
        SUM(kgProduced) AS DayKgProduced, 
    FROM dbo.CaseLots 
    WHERE DateProduced BETWEEN '2013-10-01' AND '2013-10-02' 
    GROUP BY DateProduced
) DailyTotals
INNER JOIN dbo.Budget b ON DailyTotals.DateProduced = b.OperatingDate

首先,SUM生成每个CaseLot而不必SUM BudgetHours。如果您在上面的查询中使用SELECT * FROM,则会看到:

Date        DayKgProduced  BudgetHours
2013-10-01  20000          24 
2013-10-02  10000          24

但是你想要整体总数,所以我们SUM那些每日价值,正确地产生:

TotalProduction  TotalBudgetHours
30000            48