用于查询定期日历事件的 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 | 倾向于 | 重复输入 | 最后一次发生

【问题讨论】:

dtstartdtendEvents 中的唯一字段吗?或者您是否还存储了重复和最后一次出现的日期?所有重复发生的事件都有结束日期吗?还是可以永远持续下去? 您的重复数据列的名称和类型是什么? @Bohemian 重复数据列是重复类型,取值 -1 = 不重复,0 = 每天重复,1 = 每周重复,2 = 每月重复,5 = 每年重复。 【参考方案1】:

我想不出有一条 SQL 语句可以检查重复事件的重叠事件,但这里有一些建议。

    如果您的所有重复事件都有明确的结束日期,您可以创建一个表EventInstance,其中包含EventIDStartTimeEndTime。然后在Event 表上编写AFTER INSERTAFTER UPDATEAFTER 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 &lt; DTEND AND :e &gt; DTSTART(假设输入和数据有效)。如果这两个条件中的任何一个为假,则事件不会重叠。 是的,你是对的。只要:s:e 之前并且DTSTARTDTEND 之前,我的情况就会“崩溃”到你的情况。【参考方案3】:

这将是一些相当多的代码。我将概述对每周重复事件 A 的检查,该检查在“无”发生事件 B 之前开始。

    如果两者都是“无”,请进行检查。 如果它们不重叠,则将 A.dtstart 和 dtend 添加 7 天。 再次检查。 重复直到检查成功或 A.dtstart > B.dtend。

对每日、每月等使用此变量的变体。如果这两个事件是一个相同的发生时间表,这也可以。

如果他们在不同的,你需要有第二个外循环迭代另一个间隔。停止条件可能很棘手,我认为这将是天数内两个间隔大小的最小公倍数。

所有这些代码都必须用您的宿主语言完成,可以直接在 SQlite 中用作存储过程语言。如何做到这一点因宿主语言而异。

【讨论】:

以上是关于用于查询定期日历事件的 SQLite 语句的主要内容,如果未能解决你的问题,请参考以下文章

ICS 在定期日历事件中更新这个和未来

Android 数据存储 - 文件与 SQLite

SQL注入之bWAPP之sqli_11.php

Android日期SQLite SimpleDateFormat日历[重复]

iCloud日历删除事件请求不适用于caldav

Google Apps 日历 API 推送事件查询