Я строю систему пользовательских событий, и если у вас есть повторяющееся событие, которое выглядит так:
Событие А повторяется каждые 4 дня, начиная с 3 марта 2011 г.
или
Событие B повторяется каждые 2 недели во вторник, начиная с 1 марта 2011 г.
Как я могу сохранить это в базе данных таким образом, чтобы упростить поиск. Я не хочу проблем с производительностью, если есть большое количество событий, и мне приходится проходить все до конца при рендеринге календаря.
database-design
calendar
Брэндон Вамбольдт
источник
источник
1299132000
это жестко? Что это будет делать, если мне нужно получить даты появления и пользователя для указанной даты окончания?Ответы:
Хранение «простых» повторяющихся паттернов
Для моего календаря на базе PHP / MySQL я хотел хранить информацию о повторяющихся / повторяющихся событиях настолько эффективно, насколько это возможно. Я не хотел иметь большое количество строк, и я хотел легко искать все события, которые будут происходить в определенную дату.
Приведенный ниже метод отлично подходит для хранения повторяющейся информации, которая происходит через регулярные промежутки времени, например, каждый день, каждые n дней, каждую неделю, каждый месяц, каждый год и т. Д. И т. Д. Это также включает шаблоны типов каждый вторник и четверг, поскольку они хранятся отдельно, как каждую неделю, начиная со вторника, и каждую неделю, начиная с четверга.
Предполагая, что у меня есть две таблицы, одна называется
events
так:И таблица называется
events_meta
так:С repeat_start является дата без времени в качестве метки времени unix, а repeat_interval - количество секунд в интервалах (432000 - 5 дней).
repeat_interval_1 идет с repeat_start идентификатора 1. Так что, если у меня есть событие, которое повторяется каждый вторник и каждый четверг, repeat_interval будет 604800 (7 дней), и будет 2 repeat_starts и 2 repeat_intervals. Таблица будет выглядеть так:
Затем, если у вас есть календарь, который просматривает каждый день, собирая события за день, в котором он находится, запрос будет выглядеть так:
Замена
{current_timestamp}
на метку времени unix для текущей даты (минус время, поэтому значения часов, минут и секунд будут установлены на 0).Надеюсь, это поможет кому-то еще!
Хранение «сложных» повторяющихся паттернов
Этот метод лучше подходит для хранения сложных шаблонов, таких как
Event A repeats every month on the 3rd of the month starting on March 3, 2011
или
Event A repeats Friday of the 2nd week of the month starting on March 11, 2011
Я бы порекомендовал объединить это с вышеуказанной системой для большей гибкости. Таблицы для этого должны выглядеть так:
И таблица называется
events_meta
так:repeat_week_im
представляет неделю текущего месяца, которая может быть от 1 до 5 потенциально.repeat_weekday
в день недели 1-7.Теперь, предположив, что вы просматриваете дни / недели для создания представления месяца в календаре, вы можете составить запрос, подобный следующему:
Это в сочетании с описанным выше способом может быть объединено для охвата большинства повторяющихся / повторяющихся шаблонов событий. Если я что-то пропустил, пожалуйста, оставьте комментарий.
источник
AND ( ( CASE ( 1299132000 - EM1.meta_value ) WHEN 0 THEN 1 ELSE ( 1299132000 - EM1.meta_value) END ) / EM2.meta_value ) = 1
этом это/ EM2.meta_value
помещено неправильно?86400
Секунд в дне, поскольку это не учитывает переход на летнее время. Более уместно вычислять эти вещи динамически на лету и вместо этого хранитьinterval = daily
иinterval_count = 1
илиinterval = monthly
и иinterval_count = 1
.Хотя принятый в настоящее время ответ мне очень помог, я хотел бы поделиться некоторыми полезными изменениями, которые упрощают запросы и повышают производительность.
«Простые» повторяющиеся события
Для обработки событий, которые повторяются через равные промежутки времени, такие как:
или
Вы должны создать две таблицы, одна из которых называется
events
так:И таблица называется
events_meta
так:В
repeat_start
качестве даты-метки Unix без времени (1369008000 соответствует 20 мая 2013 г.), иrepeat_interval
также величину в секундах между интервалами (604800 составляет 7 дней).Зацикливая каждый день в календаре, вы можете получать повторяющиеся события с помощью этого простого запроса:
Просто замените в unix-timestamp (1299736800) каждую дату в вашем календаре.
Обратите внимание на использование по модулю (знак%). Этот символ похож на обычное деление, но возвращает «остаток» вместо частного, и поэтому он равен 0, когда текущая дата является точным кратным повторения повторения_интервала из repeat_start.
Сравнение производительности
Это значительно быстрее, чем ранее предложенный ответ на основе meta_keys, который был следующим:
Если вы запустите EXPLAIN для этого запроса, вы заметите, что он требует использования буфера соединения:
Решение с 1 объединением выше не требует такого буфера.
"Сложные" Узоры
Вы можете добавить поддержку более сложных типов для поддержки следующих типов правил повторения:
или
Ваша таблица событий может выглядеть точно так же:
Затем, чтобы добавить поддержку этих сложных правил, добавьте столбцы
events_meta
вроде так:Обратите внимание , что вам просто необходимо либо указать
repeat_interval
или наборrepeat_year
,repeat_month
,repeat_day
,repeat_week
, иrepeat_weekday
данные.Это делает выбор обоих типов одновременно очень простым. Просто переберите каждый день и введите правильные значения (1370563200 на 7 июня 2013 года, а затем год, месяц, день, номер недели и день недели следующим образом):
Это возвращает все события, которые повторяются в пятницу 2-й недели, а также любые события, которые повторяются каждую пятницу, поэтому он возвращает оба идентификатора события 1 и 2:
* Sidenote в приведенном выше SQL Я использовал индексы дня недели по умолчанию для PHP Date , поэтому «5» для пятницы
Надеюсь, это поможет другим так же, как мне помог оригинальный ответ!
источник
repeat_interval
столбец и представить его в последующих столбцах (т. Е. И т.repeat_year
Д.). Для первой строки ситуацию с повторением каждый понедельник после 20 мая 2013 г. можно представить, поместив 1 вrepeat_weekday
и*
в других столбцах.*
. Таким образом, для «каждый месяц 3-го числа» вы просто устанавливаетеrepeat_day
значение 3, остальныеrepeat
поляrepeat_interval
равны * (оставьте пустым), и установите для repeat_start тайм-код unix для 3 марта 2011 г. в качестве даты привязки.Улучшение: заменить метку времени датой
В качестве небольшого улучшения принятого ответа, который был впоследствии уточнен ahoffner - можно использовать формат даты, а не метку времени. Преимущества:
Для этого измените БД
repeat_start
на тип «дата» иrepeat_interval
теперь держите дни, а не секунды. т.е. 7 за повторение 7 дней.изменить строку sql:
чтобы:
все остальное остается прежним. Simples!
источник
Я бы следовал этому руководству: https://github.com/bmoeskau/Extensible/blob/master/recurrence-overview.md
Также убедитесь, что вы используете формат iCal, чтобы не изобретать велосипед и запомнить правило № 0: НЕ храните отдельные повторяющиеся экземпляры событий в виде строк в вашей базе данных!
источник
attendedEvent
сbaseInstanceId
иinstanceStartDate
- это, например, базовое событие, из которого вы создали повторяющееся представление календаря правил и использовали дату начала для указания информации об этом конкретном экземпляре. Тогда эта сущность также может есть что-то вроде того,attendedListId
что приводит к другому столуid
,attendedUserId
Для всех вас, кто заинтересован в этом, теперь вы можете просто скопировать и вставить, чтобы начать работу в течение нескольких минут. Я принял совет в комментариях, как мог. Дайте мне знать, если я что-то упустил.
"КОМПЛЕКСНАЯ ВЕРСИЯ":
События
events_meta
Код SQL:
также доступный как экспорт MySQL (для легкого доступа)
Пример PHP-кода index.php:
Пример PHP-кода connect.php:
Также здесь доступен код php (для лучшей читаемости):
index.php
и
connect.php.
Теперь настройка этого займет несколько минут. Не часы. :)
источник
Хотя предложенные решения работают, я пытался реализовать их с помощью полного календаря, и для каждого представления потребовалось бы более 90 обращений к базе данных (так как он загружает текущий, предыдущий и следующий месяц), что меня не слишком обрадовало.
Я нашел рекурсивную библиотеку https://github.com/tplaner/, когда вы просто сохраняете правила в базе данных и один запрос, чтобы получить все соответствующие правила.
Надеюсь, это поможет кому-то еще, так как я провел много часов, пытаясь найти хорошее решение.
Изменить: эта библиотека для PHP
источник
When
Вы должны хранить все даты восстановления в базе данных или получать все события восстановления и генерировать даты в php no в базе данных. Я прав?When
для генерации всех дат, которые заполняются из начальной сохраненной даты / правил.Почему бы не использовать механизм, похожий на задания Apache cron? http://en.wikipedia.org/wiki/Cron
Для календаря \ планирования я бы использовал немного отличающиеся значения для «битов», чтобы приспособить стандартные события повторения календаря - вместо [день недели (0–7), месяц (1–12), день месяца (1–31), час (0 - 23), мин (0 - 59)]
- Я бы использовал что-то вроде [Год (повторять каждые N лет), месяц (1–12), день месяца (1–31), неделя месяца (1–5), день недели (0–7) ]
Надеюсь это поможет.
источник
Я разработал эзотерический язык программирования только для этого случая. Самое приятное в этом то, что он не требует схем и не зависит от платформы. Вам просто нужно написать программу выбора, для вашего расписания, синтаксис которой ограничен набором правил, описанных здесь -
https://github.com/tusharmath/sheql/wiki/Rules
Правила расширяемы, и вы можете добавить любые настройки, основанные на том типе логики повторения, который вы хотите выполнять, не беспокоясь о переносе схемы и т. Д.
Это совершенно другой подход и может иметь свои недостатки.
источник
Очень похоже на события MySQL, которые хранятся в системных таблицах. Вы можете посмотреть на структуру и выяснить, какие столбцы не нужны:
источник
Стандарт RRULE создан именно для этого требования, т.е. для сохранения и понимания повторений. Microsoft и Google оба используют это в своих событиях календаря. Пожалуйста, просмотрите этот документ для более подробной информации. https://icalendar.org/iCalendar-RFC-5545/3-8-5-3-recurrence-rule.html
источник
@Rogue Coder
Это круто!
Вы можете просто использовать операцию по модулю (MOD или% в mysql), чтобы сделать ваш код простым в конце:
Вместо того:
Делать:
Чтобы пойти дальше, можно включить события, которые не повторяются вечно.
Может быть добавлено что-то вроде «repeat_interval_1_end» для обозначения даты последнего «repeat_interval_1». Это, однако, делает запрос более сложным, и я не могу понять, как это сделать ...
Может быть, кто-то может помочь!
источник
Два приведенных вами примера очень просты; они могут быть представлены в виде простого интервала (первый - четыре дня, второй - 14 дней). То, как вы смоделируете это, будет полностью зависеть от сложности ваших повторений. Если то, что у вас есть выше, действительно так просто, сохраните дату начала и количество дней в интервале повторения.
Если, однако, вам нужно поддерживать такие вещи, как
Или
Тогда это гораздо более сложная модель.
источник