1

我正在尝试创建一个活动日历,虽然最初很小,但可能会变得很大。为此,当尽可能多地尝试对它进行未来证明时,过去发生的所有事件都将从数据库中删除。但是,一旦发生重复事件以指示下一个事件何时开始,就更改它们的开始日期是不好的做法吗?这使得执行搜索查询变得更容易,因为理论上没有事件会在过去一周内开始,具体取决于数据库的更新频率。

有一个更好的方法吗?

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

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

每月:同上,但每次 + 1 个月。

每周:如上所述,但事件开始和事件完成将在每次迭代之间增加 7 天,直到事件开始 + 7 天重复 > 搜索完成。

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

但是,当我考虑为实现这一点而必须构建的查询时,我不禁认为它会非常麻烦并且可能很慢。有没有更好的方法来达到我想要的结果?我仍然没有找到一种方法来处理每月的第一个星期一或每月的最后一个星期五或每年四月的第二个星期六发生的事情。这些后一种选择甚至可能吗?

-- 编辑:添加如下:

如果我对我正在创建的内容进行更多解释,可能会有所帮助。这样就可以给予指导。

我正在创建一个网站,允许组织添加事件,无论它们是一次性的还是重复的(每天、每周、每月、一个月的第一个星期二等)。然后,该网站的用户将能够在设定的日期或两个给定的日期(可能相隔 1 天到相隔几年(很明显,未来的事件将很少或不存在,具体取决于使用的日期)。

EVENTS 表本身目前包含有关事件的大量信息,例如位置、成本、年龄组等。最好将其放在单独的表中,一旦确定事件是否在指定的搜索参数?显然,在详细的页面查看之前不需要所有这些信息,可能只是名称、位置、成本和简要说明。

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

非常感谢任何进一步的建议。

4

3 回答 3

3

无需为每次重复创建事件。存储定义事件如何重现的详细信息要好得多。这个问题已经在 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))
    )
)

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

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

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`;

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

该表dummy由一列组成,数字从 0 到您预期需要的任何数字。此示例创建一个包含足够数据的虚拟表以涵盖一个月。INSERT... SELECT...您可以使用另一个表的 AI PK轻松填充它-

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);
于 2012-03-25T22:36:47.870 回答
1

将其分解 为尚未发生的通风口准备一张表,并带有重复的事件 ID。因此,您只需将重复的 veent id 设为 null 即可。摆脱/归档过去的等。

有另一个关于重复事件的数据。

当标记为重复的事件发生时,返回重复表,检查它是否已启用(您可能希望为它们添加一个范围,即每周执行一次,持续三个月),如果一切正常,添加一条新记录下次发生。

无论如何都是一种方法,它消除了将事件启动用于两种不同事物的问题,这就是您的代码变得复杂的原因。

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

这将是一个联合查询。一个获得所有“当前工作”,与一个联合获得所有将在下个月重复出现的工作。

不能强调这一点,让数据设计正确,代码“刚刚发生”。如果您的数据在一个字段“开始日期”中服务于两种不同的需求时被弄乱了,那么每次您靠近它时,您都必须处理这种双重用途。忘记它一次,你会得到从痛苦的混乱到灾难的任何事情。

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

于 2012-03-25T17:49:07.507 回答
0

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

它还会使“每月的第三个星期四”之类的事情变得更容易一些。如果您尝试在查询中进行任何计算,这将很困难并且可能很慢。

于 2012-03-25T20:46:25.063 回答