【问题标题】:Running total over date range - fill in the missing dates在日期范围内运行总计 - 填写缺失的日期
【发布时间】:2012-02-21 17:11:39
【问题描述】:

我有下表。

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'

会导致 0111 的 800 但是...

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

【问题讨论】:

  • DATE 是 VARCHAR 还是什么类型?
  • 提示:见mysql手册dev.mysql.com/doc/refman/5.0/en/group-by-functions.html中的“GROUP BY”
  • @bumperbox - 不处理 and have the missing months displayed as well
  • 从给定的例子中,这个结果是从哪里来的? 1110 | 300
  • 请不要以DATE 之类的SQL 类型命名您的列,即使该类型的名称是列名的明显选择。从长远来看,消除类型名称和列名称歧义所花费的时间是不值得的。

标签: mysql sql gaps-and-islands


【解决方案1】:

为了满足缺少的月份,创建一个模板表来加入。

将其视为缓存。无需循环遍历和填补空白,只需在数据库中缓存一个日历即可。

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

你最终会得到类似......

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

【讨论】:

  • 这假设您使用 DATETIME 日期类型来存储您的日期。如果您使用的是 VARCHAR 或其他东西,我强烈建议您更改它。在选择数据时处理演示文稿,而不是在存储数据时处理。
【解决方案2】:

主要问题是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

【讨论】:

  • 您可以在没有辅助表的情况下通过动态使用投影序列来实现此目的。 How to generate a range of numbers in Mysql
  • “插入我的表”。是一样的……可以用来填充临时表是的,但是表是否是临时的并不重要,重要的是他需要一个辅助表来做他想做的事
  • 没有参数。我只是想指出,他可以在动态范围内以基本零成本生成小序列,尤其是 1 或 2 年的序列,而不必费心将其放入表格中。
【解决方案3】:

您还可以动态生成一个范围,将其值作为间隔传递给 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

或者类似的东西。

【讨论】:

    【解决方案4】:
    select sum(AMT) from TABLE1 group by Date
    

    【讨论】:

    • 你读过这个问题吗?这无法解决操作所遇到的任何实际问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-05
    • 2011-04-02
    • 2015-01-14
    • 2020-07-05
    • 1970-01-01
    • 2015-10-19
    • 2018-06-24
    相关资源
    最近更新 更多