Оператор SQLite для запроса повторяющихся событий календаря - PullRequest
6 голосов
/ 04 августа 2011

Я разрабатываю приложение календаря, которое повторяется Нет, Ежедневно, Еженедельно, Ежемесячно и Ежегодно.Одно из моих требований заключается в том, что «Никакие два события не должны перекрываться» Имя таблицы, в которой хранятся данные

События

поля

dtstart - время начала события

dtend - время окончания события

Рассмотрим следующие два случая,

Event115 августа, 15:00 - 16:00, повторение отсутствует

Событие2 15 августа, 14:00 - 17:00, повторение отсутствует

В приведенном выше случае следующий SQL-запрос работает как charm

String sqlQuery = "SELECT * FROM Events WHERE dtstart AND dtend BETWEEN% d AND% d";

sqlQuery = String.format (sqlQuery, dtstart, dtend);

Теперь рассмотрим второй случай.

Событие 1 15 августа 3: С 00:00 до 16:00. Периодичность - ежедневно до 20 августа

Событие2 18 августа, 14:00 - 17:00. Повторение отсутствует

В случае двух моих sqlQuery не удается, так как он проверяет время начала и окончания события на одну и ту же дату (18 августа).В моем случае мой запрос должен показывать конфликтующее время для 15 августа.

Пожалуйста, помогите мне с запросом SQL, чтобы проверялись даже повторяющиеся события.

В таблице событий, Я сохраняю время начала, время окончания, дату последнего вхождения и тип вхождения.

Схема базы данных выглядит следующим образом

Имя таблицы: События

Заголовок | dtstart | dtend | повторить Тип | последнее вхождение

Ответы [ 3 ]

1 голос
/ 08 августа 2011

Я предполагаю, что вы хотите определить, перекрывается ли одно вновь вставленное (или обновленное) событие ( не , есть ли какое-либо из событий, уже находящихся в базе данных, имеет перекрытия), верно?

Если это так, вы можете процедурно (на вашем клиентском языке) сгенерировать все интервалы начала / окончания [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», они никогда не могут совпадать независимо от «повторного типа».
  • Etc ...

Если вы действительно хотите, чтобы вся ваша обработка на стороне базы данных и требовала производительности (запроса), вы, вероятно, смотрите на какую-то геопространственную / многомерную индексацию и вам нужно будет на самом деле сохранить событие повторения в базе данных, чтобы их можно было проиндексировать, что, вероятно, снизит производительность вставки. Я не знаком с SQLite и с тем, поддерживает ли он такой вид индексации ...

1 голос
/ 15 августа 2011

Это будет довольно много кода.Я выделю проверку для еженедельного события повторного события A, которое начинается перед событием «none» B.

  1. Выполните проверку, как если бы оба были «none».
  2. Если они не перекрываются, добавьте 7 дней к A.dtstart и dtend.
  3. Проверьте снова.
  4. Повторяйте до тех пор, пока проверка не пройдет успешно или A.dtstart> B.dtend.

Используйте варианты этого для ежедневного, ежемесячного и т. Д. Если оба события являются одним и тем же расписанием событий, это тоже работает.

Если они находятся на разных, вам нужно иметь второй внешний цикл, который повторяется по другому интервалу.Условие остановки может быть сложным, я думаю, что это будет что-то вроде наименьшего общего кратного обоих размеров интервалов в днях.

Весь этот код должен быть выполнен на вашем языке хоста, что может использоваться в качестве языка хранимых процедур в SQlite напрямую.Как это сделать, зависит от языка хоста.

1 голос
/ 04 августа 2011

Я не могу вспомнить ни одного оператора SQL, который проверяет перекрывающиеся события с повторением, но вот некоторые предложения.

  1. Если все ваши повторяющиеся события имеют определенную дату окончанияВы можете создать таблицу EventInstance, состоящую из EventID, StartTime и EndTime.Затем вы пишете AFTER INSERT, AFTER UPDATE и AFTER DELETE Триггеры в вашей таблице Event, чтобы обновить все экземпляры, хранящиеся в EventInstance.Тогда ваш запрос может быть использован в таблице EventInstance.Но у меня нет опыта работы с SQLite, поэтому я не знаю, поддерживает ли он триггеры.

  2. Напишите хранимую процедуру в базе данных, чтобы проверить ее с процедурным кодом (сноваесли SQLite поддерживает это)

  3. Проверьте перекрывающиеся события в коде Java.

...