将数据库中的开始日期更改为事件的下一次发生是好是坏


Is it good or bad practise to alter start dates in a database to the next occurrence of an event?

我正在尝试创建一个事件日历,虽然最初很小,但后来可能会很大。为此,当试图尽可能地对其进行未来验证时,将从数据库中删除过去发生的所有事件。然而,一旦重复发生的事件发生,就改变其开始日期以指示下一个事件何时开始,这是不是一种糟糕的做法?这使得执行搜索查询更加容易,因为理论上,根据数据库的更新频率,过去一周内不会发生任何事件。

有更好的方法吗?

我目前的意图是有一个表,列出事件的详细信息,并列出一列,无论是每年、每月、每周还是每天的重复。当有人搜索两个日期之间的事件时,我只需查看每一行并检查是否(EVENT START<=SEARCH FINISH&&EVENT FINISH>=SEARCH START)。然后,它会得到所有可能的事件,然后需要检查重复发生的事件,看看它们是否在给定的时间段内发生。这就是我有点困惑的地方,关于如何具体实现这一点。我的想法如下:

每年:如果事件开始+1年<=搜索结束||事件结束+1年>=搜索开始;重复+2年等,直到事件开始+无年份>搜索结束。

每月:如上所述,但每次+1个月。

每周:如上所述,但每次迭代的事件开始和事件结束间隔为7天,直到事件开始+7天重复>搜索结束。

每日:如上所述,但没有天数差异,而不是一周7天。这可以用于指定诸如每14天(两周)、每10天之类的事情。甚至每周都可以使用这种方法。

然而,当我想到为了实现这一点而必须构建的查询时,我不禁认为它会非常繁琐,而且可能很慢。有没有更好的方法来实现我想要的结果?我仍然没有找到一种方法来做每年四月的第一个星期一、最后一个星期五或第二个星期六发生的事情。后一种选择可能吗?

--编辑:添加到下面:

如果我多解释一下我正在创造的东西,这可能会有所帮助。这样就可以在这方面提供指导。

我正在创建一个网站,允许组织添加活动,无论是一次性的还是重复的(每天、每周、每月、一个月的第一个星期二等)。然后,该网站的用户将能够在指定日期或两个给定日期之间搜索选定距离(任意10、25、50、100英里,全国范围内)内的事件,这些日期可能相隔1天,也可能相隔几年(很明显,根据使用的日期,未来发生的事件将是最小的或不存在的)。

EVENTS表本身目前保存了许多关于事件的信息,如位置、成本、年龄组等。将其放在一个单独的表中会更好吗?一旦确定事件是否在指定的搜索参数内,就会查找该表?显然,在详细的页面视图之前,并不需要所有这些信息,可能只是名称、位置、成本和简要描述。

我很感激有很多方法可以剥猫的皮,但我不确定如何剥这只猫的皮。我正在努力解决的最大问题是如何构建数据结构,以便查询知道递归是否在指定日期内。此外,考虑到计算2 lat/long之间距离的数学计算相对复杂,我需要能够将此计算构建到我的查询中,否则我无论如何都会用PHP进行计算。诚然,以这种方式处理的结果会更少,但仍需要这样做。

如有进一步建议,不胜感激。

没有必要为每次重复创建事件。最好存储定义事件如何重现的详细信息。这个问题在SO上已经回答了很多次。

一种方法是使用这样的结构-

tblEvent
--------
id
name
description
date
tblEventRecurring
-----------------
event_id
date_part
end_date

然后您可以使用这样的查询来检索事件-

SELECT *
FROM `tblEvent`
LEFT JOIN `tblEventRecurring`
    ON `tblEvent`.`id` = `tblEventRecurring`.`event_id`
WHERE (`tblEvent`.`date` = CURRENT_DATE AND `tblEventRecurring`.`event_id` IS NULL)
OR (
    CURRENT_DATE BETWEEN `tblEvent`.`date` AND `tblEventRecurring`.`end_date`
    AND (
        (`tblEventRecurring`.`date_part` = 'D') OR
        (`tblEventRecurring`.`date_part` = 'W' AND DAYOFWEEK(`tblEvent`.`date`) = DAYOFWEEK(CURRENT_DATE)) OR
        (`tblEventRecurring`.`date_part` = 'M' AND DAYOFMONTH(`tblEvent`.`date`) = DAYOFMONTH(CURRENT_DATE))
    )
)

UPDATE添加了以下返回给定日期范围的事件的示例。

当返回给定日期范围的日期时,您可以将上述查询加入表示日期范围的表-

SET @start_date = '2012-03-26';
SET @end_date = '2012-04-01';
SELECT *
FROM (
    SELECT @start_date + INTERVAL num DAY AS `date`
    FROM dummy
    WHERE num < (DATEDIFF(@end_date, @start_date) + 1)
) AS `date_list`
INNER JOIN (
    SELECT `tblEvent`.`id`, `tblEvent`.`date`, `tblEvent`.`name`, `tblEventRecurring`.`date_part`, `tblEventRecurring`.`end_date`
    FROM `tblEvent`
    LEFT JOIN `tblEventRecurring`
        ON `tblEvent`.`id` = `tblEventRecurring`.`event_id`
    WHERE `tblEvent`.`date` BETWEEN @start_date AND @end_date
    OR (`tblEvent`.`date` < @end_date AND `tblEventRecurring`.`end_date` > @start_date)
) AS `events`
    ON `events`.`date` = `date_list`.`date`
    OR (
        `date_list`.`date` BETWEEN `events`.`date` AND `events`.`end_date`
        AND (
            (`events`.`date_part` = 'D') OR
            (`events`.`date_part` = 'W' AND DAYOFWEEK(`events`.`date`) = DAYOFWEEK(`date_list`.`date`)) OR
            (`events`.`date_part` = 'M' AND DAYOFMONTH(`events`.`date`) = DAYOFMONTH(`date_list`.`date`))
        )
    )
WHERE `date_list`.`date` BETWEEN @start_date AND @end_date
ORDER BY `date_list`.`date`;

如果愿意,可以用PHP变量替换SQL变量。要显示没有任何事件的天数,可以将两个派生表date_listevents之间的INNER JOIN更改为LEFT JOIN。

dummy由一列组成,其中包含从0到您预期需要的任何数字。本例创建了一个包含足够一个月数据的伪表。您可以在另一个表的AI PK上使用INSERT... SELECT...轻松填充它

CREATE TABLE `dummy` (
    `num` SMALLINT UNSIGNED NOT NULL PRIMARY KEY
);
INSERT INTO `dummy` VALUES
    (00), (01), (02), (03), (04), (05), (06), (07), (08), (09),
    (10), (11), (12), (13), (14), (15), (16), (17), (18), (19),
    (20), (21), (22), (23), (24), (25), (26), (27), (28), (29),
    (30), (31);

分解为尚未发生的事件创建一个表,其中包含一个重复事件ID。因此,您可以在其中插入一个重复veent ID为null的事件。清除/归档过去的文件等

请另存一份关于重复事件的数据。

当一个标记为重复发生的事件发生时,返回到重复表,检查它是否已启用(您可能想向它们添加一个范围,即在三个月内每一周添加一次),如果一切正常,则在下次发生时添加一个新记录。

无论如何,有一种方法可以做到这一点,它消除了将事件启动用于两种不同事情的问题,这就是代码变得越来越复杂的原因。

如果你想从中获得未来的工作。下个月要做的一切。

它将是一个联合查询。一个获得所有"当前工作",另一个获得下个月将重复出现的所有工作。

再怎么强调也不为过,只要数据设计正确,代码"就会发生"。如果你的数据被搞砸了,因为一个字段"开始日期"满足了两种不同的需求,那么每次你接近它时,你都必须处理这种双重用途。忘记它一次,你会得到任何东西,从痛苦的混乱到灾难。

添加Recurring_Start_Date列会比你当前的计划更好,不是吗?你不会问这个问题,因为你的数据符合你的需求。

我认为您搜索事件的频率要比创建新事件的频率高得多。在事件创建过程中,我会为事件的每次发生创建记录,直到合理的时间(可能是接下来的一两年)。

这也会让"每个月的第三个星期四"这样的事情变得更容易一些。如果您试图在查询中进行任何计算,这将是困难的,而且可能很慢。