运行总计超过日期范围 - 填写缺少的日期

时间:2012-02-21 17:11:40

标签: mysql sql gaps-and-islands

我有下表。

DATE  | AMT
10/10 | 300
12/10 | 300
01/11 | 200
03/11 | 100

如何获得每月总数?结果如 -

DATE | TOT
1010 | 300
1110 | 300
1210 | 600 
0111 | 800
0211 | 800
0311 | 900

这样的sql语句
SELECT SUM(AMT) FROM TABLE1 WHERE DATE BETWEEN '1010' AND '0111'

会导致800为0111,但......

注意没有日期限制。这是我的困境。如何在不对所有日期执行循环的情况下填充此列并显示缺少的月份?

4 个答案:

答案 0 :(得分:2)

为了迎合缺失的月份,请创建一个加入的模板表。

将其视为缓存。而不是循环填补空白,只需在数据库中缓存日历。

您甚至可以将多个日历(月初,周开始,银行假日,工作日等)全部合并到一个表中,并附带一堆搜索标记和索引。

你最终得到像......

SELECT
  calendar.date,
  SUM(data.amt)
FROM
  calendar
LEFT JOIN
  data
    ON  data.date >= calendar.date
    AND data.date <  calendar.date + INTERVAL 1 MONTH
WHERE
      calendar.date >= '20110101'
  AND calendar.date <  '20120101'
GROUP BY
  calendar.date

修改

我刚注意到OP需要一个总计。

这在SQL中是可能的,但它非常效率低下。原因是一个月的结果不用于计算下个月。相反,必须再次计算整个运行总量。

出于这个原因,通常强烈建议您按上述方法计算月度总数,然后使用您的应用程序进行迭代并计算运行总值。

如果真的必须在SQL中执行,那就像......

SELECT
  calendar.date,
  SUM(data.amt)
FROM
  calendar
LEFT JOIN
  data
    ON  data.date >= @yourFirstDate
    AND data.date <  calendar.date + INTERVAL 1 MONTH
WHERE
      calendar.date >= @yourFirstDate
  AND calendar.date <  @yourLastDate
GROUP BY
  calendar.date

答案 1 :(得分:0)

主要问题是and have the missing months displayed as well? 我没有看到如何使用包含要显示的月\年组合的辅助表来执行此操作:

create table table1(
date datetime,
amt int
)
insert into table1 values ('10/10/2010',100)
insert into table1 values ('12/12/2010',200)
insert into table1 values ('01/01/2011',50)
insert into table1 values ('03/03/2011',500)

truncate table #dates
create table #dates(
_month int,
_year int
)
insert into #dates values(10,2010)
insert into #dates values(11,2010) --missing month
insert into #dates values(12,2010)
insert into #dates values(01,2011)
insert into #dates values(02,2011)--missing month
insert into #dates values(03,2011)


select D._month, D._year, sum(amt)
from #dates D left join TABLE1 T on D._month=month(T.date) and D._year=year(T.date)
group by D._month, D._year

答案 2 :(得分:0)

您还可以动态生成范围,将其值作为间隔传递给DATE_ADD,并基本上投射一系列月份值。

正如@Dems所说,你需要有一个相关的子查询来计算运行总数,这将是非常低效的,因为它将在内部运行一个嵌套循环。

要了解如何生成序列,请在此处查看我的帖子: How to generate a range of numbers in Mysql

结束查询应该如下所示:(顺便说一下,你应该有一个日期列,而不是这个varchar混乱)。

/*NOTE: This assumes a derived table (inline view) containing the sequence of date values and their corresponding TOT value*/
SELECT
  DATEVALUES.DateValue,
  (
  SELECT SUM(TABLE1.AMT) FROM TABLE1 WHERE TABLE1.DateValue <= DATEVALUES.DateValue)
  ) AS RunningSubTotal
FROM
  DATEVALUES

或类似的东西。

答案 3 :(得分:-2)

select sum(AMT) from TABLE1 group by Date