2012-02-21 32 views
2

我有下表。超过日期范围的运行总计 - 填写缺失日期

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,但...

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

+3

DATE是VARCHAR还是什么类型? – rkosegi 2012-02-21 17:13:29

+1

提示:请参阅mysql手册中的“GROUP BY”http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html – bumperbox 2012-02-21 17:13:37

+0

@bumperbox - 不处理'并且丢失也显示月份' – MatBailie 2012-02-21 17:17:13

回答

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

这假设您使用DATETIME日期类型来存储日期。如果你使用VARCHAR或者其他的东西,我强烈建议你改变它。在选择数据时处理演示,而不是在存储数据时处理演示。 – MatBailie 2012-02-21 17:18:08

-2
select sum(AMT) from TABLE1 group by Date 
+1

你读过这个问题了吗?这未能解决该操作所遇到的任何实际问题。 – MatBailie 2012-02-21 17:21:24

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 
+0

您可以通过即时使用投影序列,在没有辅助表的情况下实现此目的。 [如何在Mysql中生成一系列数字](http://stackoverflow.com/questions/186756/how-to-generate-a-range-of-numbers-in-mysql/187410#187410) – 2012-02-21 17:35:55

+0

“INSERT INTO myTable的”。它是一样的东西......可以用来填充临时表是的,但是如果表是临时的或者不是无关紧要,重要的是他需要一个辅助表来做他想做的事 – Diego 2012-02-21 17:48:13

+0

那里没有参数。我只想指出,他可以在一个动态范围内以基本上零成本生成小的序列,尤其是1到2年,而不用费心把它们放到表格中。 – 2012-02-21 17:54:26

0

您也可以在fl中生成一个范围y,将其值作为间隔传递给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 

或类似的东西。