我有这个现有的架构,其中“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
想一个图表,显示每个人随着时间的推移,或计算燃尽图中的“资源”值。 我可以使用应用层中的过程代码轻松完成此操作,但更喜欢更好,更快的解决方案。
答案 0 :(得分:2)
为了使远程有效,我建议创建一个calendar
表。一个包含每个感兴趣的日期。然后,您可以将其用作加入数据的模板。
同样,如果您有person
表作为结果名称维度的模板,事情会进一步改善。
然后,您可以在联接中使用相关的子查询,以选择Schedule
中与您创建的calendar
,person
模板匹配的记录。
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的空白。
(如果您的客户端代码缓慢执行此操作,请发布另一个检查该代码的问题。如果对数据进行了排序,那么在大多数语言中这都非常快。)