我会制作一个包含各种可能条件的表格:
table repetition (
event_id int foreign key,
first_date date not null,
last_date date not null,
day_period int null, -- 3 = every 3 days
day_of_month int null, -- 1..31
-- day_of_week int null, -- 0..6, if needed
-- whatever else
)
现在您可以轻松选择今天发生的事件:
select event.*
from repetition
where
-- (day_of_week is null or day_of_week = :current_day_of_week) and
(day_of_month is null or day_of_month = :current_day_of_month) and
(day_period is null or (:current_date - first_date) mod day_period = 0) and
first_date <= :current_date and
last_date >= :current_date
join event on event.id = event_id
(first_date, last_date) 的索引将使查询计划足够高效(索引范围扫描)。
要使范围“无限”,只需将last_date 放在遥远的未来,例如 3000 年。
要处理事件中的“单个”更改,您可以将change_of 列添加到event 表并使其引用回event.id。对于常规事件,它为空。对于更改事件,它存储change_of 指向的事件的覆盖信息。如果您获取当天的两个事件,其中一个有 change_of 指向另一个事件,则您使用来自覆盖事件记录的数据,并忽略 change_of 引用的记录。对于一次性更改,last_date = first_date。
这还允许添加可能有用的重复更改(每隔一天的常规处方和每 14 天更改一次),以及更改时的更改,您可能会通过输入逻辑或触发器来避免这些更改。