在一段时间内继续最近的值

时间:2012-02-21 12:57:57

标签: mysql sql

我有这个现有的架构,其中“schedule”表看起来像这样(非常简化)。

CREATE TABLE schedule (
  id           int(11) NOT NULL AUTO_INCREMENT,
  name         varchar(45),
  start_date   date,
  availability int(3),
  PRIMARY KEY (id)
);

对于每个人,它指定可用于此项目的开始日期和工作时间百分比。可用性百分比隐式继续,直到指定了更新的值。 例如,参加一个持续时间为2012-02-27至2012-03-02的项目:

id | name | start_date | availability
-------------------------------------
 1 |  Tom | 2012-02-27 |          100 
 2 |  Tom | 2012-02-29 |           50
 3 |  Ben | 2012-03-01 |           80

所以Tom于2月27日全职开始,直到2月29日,从那时起,他将只有50%的工作时间。 Ben只在3月1日开始,只有80%的时间。

现在的目标是“规范化”这个稀疏数据,以便每个人都有一个结果行,并且可用性来自最后一天:

name | start_date | availability
--------------------------------
 Tom | 2012-02-27 |          100 
 Tom | 2012-02-28 |          100
 Tom | 2012-02-29 |           50
 Tom | 2012-03-01 |           50
 Tom | 2012-03-02 |           50
 Ben | 2012-02-27 |            0 
 Ben | 2012-02-28 |            0
 Ben | 2012-02-29 |            0
 Ben | 2012-03-01 |           80
 Ben | 2012-03-02 |           80

想一个图表,显示每个人随着时间的推移,或计算燃尽图中的“资源”值。 我可以使用应用层中的过程代码轻松完成此操作,但更喜欢更好,更快的解决方案。

1 个答案:

答案 0 :(得分:2)

为了使远程有效,我建议创建一个calendar表。一个包含每个感兴趣的日期。然后,您可以将其用作加入数据的模板。

同样,如果您有person表作为结果名称维度的模板,事情会进一步改善。

然后,您可以在联接中使用相关的子查询,以选择Schedule中与您创建的calendarperson模板匹配的记录。

SELECT
  *
FROM
  calendar
CROSS JOIN
  person
LEFT JOIN
  schedule
    ON  schedule.name       = person.name
    AND schedule.start_date = (SELECT MAX(start_date)
                                 FROM schedule
                                WHERE name = person.name
                                  AND start_date <= calendar.date)
WHERE
      calendar.date >= <yourStartDate>
  AND calendar.date <= <yourEndDate>
  etc


但是,通常以其他两种方式处理它更有效......

首先不要在数据中留有空隙。有一个夜间批处理过程,或其他一些确保填充所有相关数据点的业务逻辑。

或在您的客户端处理它。将报表中的每个维度(数据和名称)作为单独的数据集作为模板返回,然后将数据作为最终数据集返回。您的客户可以对数据进行迭代并根据需要填写空白。这是更多的代码,但实际上可以使用更少的资源而不是尝试填补SQL的空白。

(如果您的客户端代码缓慢执行此操作,请发布另一个检查该代码的问题。如果对数据进行了排序,那么在大多数语言中这都非常快。)