在MySQL数据库中存储每年可重复的值

时间:2010-03-09 19:09:15

标签: mysql database database-design datetime date

过去几天我一直在我的桌子上敲我的头,所以我转向你,Stack Overflow。

我正在处理的软件有时间敏感的数据。通常的解决方案是有效和有效期。

EFF_DT      XPIR_DT     VALUE
2000-05-01  2000-10-31  100
2000-11-01  (null)      90

这很容易。不幸的是,我们需要在未来任意一年中重复的数据。换句话说,每个5月1日(从2000年开始)我们可能希望有效值为100,而每个11月1日我们可能希望将其更改为90.

这可能是很长时间(> 50年),所以我不想只创建一百条记录。即,我不想这样做:

EFF_DT      XPIR_DT     VALUE
2000-05-01  2000-10-31  100
2000-11-01  2001-04-30  90
2001-05-01  2001-10-31  100
2001-11-01  2002-04-30  90
2002-05-01  2002-10-31  100
2002-11-01  2003-04-30  90
...
2049-05-01  2049-10-31  100
2049-11-01  2050-04-30  90
2050-05-01  2050-10-31  100
2050-11-01  2051-04-30  90

这些值也可能随时间而变化。 2000年之前的值可能是恒定的(没有翻转),未来十年的值可能与上一个值不同:

EFF_DT      XPIR_DT     REPEATABLE  VALUE
1995-01-01  2000-04-30  false       85
2000-05-01  2010-04-30  true        100
2000-11-01  2010-10-31  true        90
2010-05-01  (null)      true        120
2010-11-01  (null)      true        115

我们已经有一个文本文件(来自遗留应用程序)以非常接近的形式存储数据,因此尽可能地坚持这种类型的结构是有好处的。

然后问题在于检索:哪个值适用于今天,2010-03-09?

似乎最好的方法是找到每个生效日期(所有活动行)的最新实例,然后查看哪个是最大的。

EFF_DT      MOST_RECENT XPIR_DT     VALUE
2000-05-01  2009-05-01  2010-04-30  100
2000-11-01  2009-11-01  2010-10-31  90

今天的价值是90,因为2009-11-01比2009-05-01晚。

On,比如,2007-06-20:

EFF_DT      MOST_RECENT XPIR_DT     VALUE
2000-05-01  2007-05-01  2010-04-30  100
2000-11-01  2006-11-01  2010-10-31  90

自2007-05-01以来,该值将为100,比2006-11-01更晚。

使用MySQL日期函数,计算MOST_RECENT字段的最有效方法是什么?

或者,有人能想到更好的方法吗?

语言是Java,如果重要的话。谢谢大家!

3 个答案:

答案 0 :(得分:2)

假设您想要的'日期'是'2007-06-20'。

你需要将非重复元素与重复元素结合起来,这样你就可以做这样的事情(未经测试,可能需要一些思考,但应该给你一般的想法):

select * from (
  select * from mytable 
  where 
    repeatable = false
    and 
    EFF_DT <= '2007-06-20' < XPIR_DT
  union all
  select * from mytable
  where
    repeatable = true
    and EFF_DT <= str_to_date(concat("2007", "-", month(EFF_DT), "-", day(EFF_DT)), "%Y-%m-%d") < XPIR_DT
)
order by EFF_DT desc limit 1

答案 1 :(得分:1)

我不得不通过定期约会来做类似的事情。事件,您可能会发现MySQL对于您不想要的“静态”日期样式会更加满意 - 每个重复的实例拼写成数百行。

如果可能的话,我会考虑创建一个单独的表来存储它们,同时保持它们的有效/过期日期(以匹配旧数据和作为父项),以及1:多之间的关系两个表(即引用原始PK的展平数据上的“event_id”)。编写所有这些记录显然需要更长时间,但它直接减轻了读取它们的负担(通常需要更快的事情)。

在给定公共间隔的情况下,创建存储过程或外部程序来处理重新计算flat start_date / end_date / value表应该是相当基本的。然后,查询数据可以像WHERE @somedate BETWEEN start_date AND end_date一样简单,而不是越来越复杂的转换&amp;日期数学。

同样,INSERT和UPDATE会更慢,但“数百行”甚至没有触及MySQL的能力。如果它只是2个日期,一个int,以及某种类型的int键,那么写几百条记录不应该只需几秒钟就可以在一个低于标准的服务器上运行。如果我们正在谈论数百万条记录,那么也许可以调整一些东西(你真的需要提前50年跟踪还是只需要接下来的5年?可以通过cron等将重新计算转移到非高峰时间),但即便如此,MySQL也只是与每次计算差异相比,它更有效。

也许有兴趣:What's the best way to model recurring events in a calendar application?&amp; Data structure for storing recurring events?

答案 2 :(得分:0)

这是一个可用于计算数据集的最新EFF_DT的查询。你必须在那里填写where子句,因为我不确定这些数据是如何组织的。

select EFF_DT  form  date_table where 1 order by EFF_DT desc limit 1

90和100的触发器更复杂,但你应该能够使用mysql data and time functions来处理这个问题。这是一个棘手的问题,我并不是100%想要做的事情。但是,此查询检查XPIR_DT的月份是否大于5月(第5个月)但小于11月(第11个月)。如果这是真的那么sql查询将返回90,如果它是false,那么你将得到100.

select if((month(XPIR_DT)>=5) and (month(XPIR_DT)<11),90,100) from date_table where id=1