用于查询定期日历事件的 SQLite 语句
Posted
技术标签:
【中文标题】用于查询定期日历事件的 SQLite 语句【英文标题】:SQLite statement to query for Recurring Calendar Events 【发布时间】:2011-10-19 22:06:23 【问题描述】:我正在设计一个日历应用程序,它重复无、每日、每周、每月和每年。 我的要求之一是“两个事件不应重叠” 我存储数据的表的名称
活动
字段
dtstart - 事件开始时间
dtend - 事件结束时间
考虑以下两种情况,
事件 1 8 月 15 日下午 3:00 - 下午 4:00 重复 - 无
事件 2 8 月 15 日下午 2:00 - 下午 5-00 重复 - 无
在上述情况下,以下 SQL 查询的工作方式与魅力相似
String sqlQuery = "SELECT * FROM 事件 WHERE dtstart AND dtend 在 %d 和 %d 之间";
sqlQuery = String.format(sqlQuery, dtstart, dtend);
现在,考虑情况二。
事件 1 8 月 15 日下午 3:00 - 下午 4:00 重复 - 每天到 8 月 20 日
Event2 8 月 18 日下午 2:00 - 下午 5-00 重复 - 无
如果我的两个 sqlQuery 失败,因为它会检查同一日期(8 月 18 日)的事件开始和结束时间。就我而言,我的查询应该显示 8 月 15 日的时间冲突。
请帮助我处理 SQL 查询,以便检查重复发生的事件。
在事件表中,我存储开始时间、结束时间、上次日期 发生和发生类型。
数据库方案如下
表名称:事件
标题 | dtstart | 倾向于 | 重复输入 | 最后一次发生
【问题讨论】:
dtstart
和 dtend
是 Events
中的唯一字段吗?或者您是否还存储了重复和最后一次出现的日期?所有重复发生的事件都有结束日期吗?还是可以永远持续下去?
您的重复数据列的名称和类型是什么?
@Bohemian 重复数据列是重复类型,取值 -1 = 不重复,0 = 每天重复,1 = 每周重复,2 = 每月重复,5 = 每年重复。
【参考方案1】:
我想不出有一条 SQL 语句可以检查重复事件的重叠事件,但这里有一些建议。
如果您的所有重复事件都有明确的结束日期,您可以创建一个表EventInstance
,其中包含EventID
、StartTime
和EndTime
。然后在Event
表上编写AFTER INSERT
、AFTER UPDATE
和AFTER DELETE
触发器以更新存储在EventInstance
中的所有实例。然后可以在EventInstance
表上使用您的查询。但是,我对 SQLite 没有任何经验,所以我不知道它是否支持触发器。
在数据库中编写一个存储过程,用过程代码检查它(如果 SQLite 支持它)
检查 Java 代码中的重叠事件。
【讨论】:
要求是这样的,我不必为重复创建一个新表。所有信息(开始时间、结束时间、重复、最后一次发生)都作为单个条目存储在事件表中。所以在我的情况下,我需要一个 SQL 查询来完成这个技巧......【参考方案2】:我假设您想检测单个新插入(或更新)的事件是否有重叠(不是数据库中已有的任何事件是否有重叠),对吗?
如果是这样,您可以在程序上(以您的客户端语言)根据新插入的事件的“重复类型”生成所有开始/结束间隔 [s, e]
,然后对这些间隔中的每一个执行以下查询以检测重叠(我在这里使用 Oracle 语法,我假设 SQLite 类似):
-- A time interval must be either completely "to the left" or completely
-- "to the right" of the other time interval for them not to overlap.
SELECT * FROM EVENT
WHERE
NOT(
(:s < DTSTART AND :s < DTEND AND :e < DTSTART AND :e < DTEND)
OR (:s > DTSTART AND :s > DTEND AND :e > DTSTART AND :e > DTEND)
)
但不要期望出色的性能(特别是如果您的事件有大量重复,或者如果 DTSTART/DTEND 未编入索引或 SQLite 无法正确利用该索引)。
为了提高性能,您最好将所有事件缓存在内存中并在客户端进行所有处理,这样您就可以更轻松地使用启发式方法来“短路”某些处理。例如:
如果两个事件具有相同的“重复类型”,您可以只比较它们的初始间隔而不必担心重复 - 如果它们最初不匹配,它们将永远不会匹配。 如果一个事件的“最后一次发生”早于其他事件而不是“dtstart”,则无论“重复类型”如何,它们都永远无法匹配。 等等……如果您真的想要所有处理数据库端的和(查询)性能,您可能正在查看某种地理空间/多维索引,并且您需要实际存储数据库中的事件重复,以便它们可以被索引,这可能会破坏您的插入性能。我不熟悉 SQLite 以及它是否支持这种索引...
【讨论】:
大部分检查都是多余的。这就足够了::s < DTEND AND :e > DTSTART
(假设输入和数据有效)。如果这两个条件中的任何一个为假,则事件不会重叠。
是的,你是对的。只要:s
在:e
之前并且DTSTART
在DTEND
之前,我的情况就会“崩溃”到你的情况。【参考方案3】:
这将是一些相当多的代码。我将概述对每周重复事件 A 的检查,该检查在“无”发生事件 B 之前开始。
-
如果两者都是“无”,请进行检查。
如果它们不重叠,则将 A.dtstart 和 dtend 添加 7 天。
再次检查。
重复直到检查成功或 A.dtstart > B.dtend。
对每日、每月等使用此变量的变体。如果这两个事件是一个相同的发生时间表,这也可以。
如果他们在不同的,你需要有第二个外循环迭代另一个间隔。停止条件可能很棘手,我认为这将是天数内两个间隔大小的最小公倍数。
所有这些代码都必须用您的宿主语言完成,可以直接在 SQlite 中用作存储过程语言。如何做到这一点因宿主语言而异。
【讨论】:
以上是关于用于查询定期日历事件的 SQLite 语句的主要内容,如果未能解决你的问题,请参考以下文章