【问题标题】:Filling date gaps with most recent value用最新值填补日期空白
【发布时间】:2012-01-13 09:14:49
【问题描述】:

我正在我的公司开发一个脚本,该脚本将从我们的 SCM 中提取有关源代码活动的信息,例如随时间变化的给定产品的行数。给定产品在同一天发生的所有更改都合并到 mySQL 表中的一条记录中,如下所示:

+------------+-------+------+
| date       | prod  | line |
+------------+-------+------+
| 2011-11-25 | prod2 |  471 |
| 2011-11-28 | prod2 |  389 |
+------------+-------+------+

然后我使用内部连接和求和复制带有累积结果的表:

+------------+-------+------+
| date       | prod  | line |
+------------+-------+------+
| 2011-11-25 | prod2 |  471 |
| 2011-11-28 | prod2 |  860 |
+------------+-------+------+

现在,我想创建一个表,其中每个产品每天都有一条记录。我已经能够通过加入日历表来做到这一点。但是,在创建新记录时,line 字段应填充该产品的最新累积值,而不是一些硬编码的默认值,如 NULL 或 0:

+------------+-------+------+
| date       | prod  | line |
+------------+-------+------+
| 2011-11-25 | prod2 |  471 |
| 2011-11-26 | prod2 |  471 |
| 2011-11-27 | prod2 |  471 |
| 2011-11-28 | prod2 |  860 |
+------------+-------+------+

到目前为止,我已经以两种不满意的方式解决了这个问题:

  1. 先填写日期间隔,然后计算累计和
  2. 循环遍历最终表格的每个元素,将最新的非空元素保存在 @user 变量中。

一旦我的表变得足够大,第一个解决方案就会变得非常低效。第二个解决方案完成了工作,但我一直在尝试找到一个更优雅的解决方案。下面是生成带有 NULL 的表的代码:

INSERT INTO final SELECT d.date,f.prod,p.line
FROM calendar AS d
CROSS JOIN
    (SELECT DISTINCT prod FROM cumulative) AS f
LEFT JOIN cumulative AS p USING (date,prod) ;

有什么想法吗?我正在使用 MySQL。

【问题讨论】:

  • 为什么要创建的不是一个,而是两个冗余表?

标签: mysql sql


【解决方案1】:

似乎最明智的做法是每天存储一行,如果没有更改行,则为零。这将消除在日历表上连接的需要。

所以你的源表看起来不像这样

+------------+-------+------+
| date       | prod  | line |
+------------+-------+------+
| 2011-11-25 | prod2 |  471 |
| 2011-11-28 | prod2 |  389 |
+------------+-------+------+

看起来像这样。

+------------+-------+------+
| date       | prod  | line |
+------------+-------+------+
| 2011-11-25 | prod2 |  471 |
| 2011-11-26 | prod2 |    0 |
| 2011-11-27 | prod2 |    0 |
| 2011-11-28 | prod2 |  389 |
+------------+-------+------+

至于运行总和本身,您的报表编写器可能比 SQL 更快地完成此操作。如果 MySQL 支持窗口函数,你只需要写类似

select date, prod, 
       sum(line) over (partition by prod order by date)
from prod

尽管如此,您的报告编写器可能会更快。

在不支持窗口函数的平台上,您只需要在子查询中求和即可。

select p1.prod, p1.date, 
       (select sum(line) from prod 
        where prod = p1.prod and date <= p1.date) as num_lines
from prod p1
order by p1.prod, p1.date

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-14
    • 2013-06-21
    • 2010-12-25
    • 2014-12-17
    • 1970-01-01
    相关资源
    最近更新 更多