Estoy creando un sistema de eventos personalizado, y si tiene un evento repetitivo que se ve así:
El evento A se repite cada 4 días a partir del 3 de marzo de 2011.
o
El evento B se repite cada 2 semanas el martes a partir del 1 de marzo de 2011
¿Cómo puedo almacenar eso en una base de datos de manera que sea fácil de buscar? No quiero problemas de rendimiento si hay una gran cantidad de eventos, y tengo que revisar todos y cada uno al representar el calendario.
database-design
calendar
Brandon Wamboldt
fuente
fuente
1299132000
está codificado? ¿Qué hará esto si necesito obtener las fechas de ocurrencia y el usuario para la fecha de finalización dada?Respuestas:
Almacenar patrones repetitivos "simples"
Para mi calendario basado en PHP / MySQL, quería almacenar información de eventos recurrentes / recurrentes de la manera más eficiente posible. No quería tener una gran cantidad de filas, y quería buscar fácilmente todos los eventos que tendrían lugar en una fecha específica.
El siguiente método es excelente para almacenar información repetitiva que ocurre a intervalos regulares, como todos los días, cada n días, todas las semanas, todos los meses, etc., etc. Esto también incluye todos los patrones de tipo martes y jueves, porque se almacenan por separado, ya que cada semana comienza un martes y cada semana comienza un jueves.
Suponiendo que tengo dos tablas, una llamada
events
así:Y una mesa llamada
events_meta
así:Dado que repeat_start es una fecha sin tiempo como marca de tiempo unix, y repeat_interval una cantidad en segundos entre intervalos (432000 son 5 días).
repeat_interval_1 va con repeat_start de la ID 1. Entonces, si tengo un evento que se repite todos los martes y todos los jueves, el repeat_interval sería 604800 (7 días), y habría 2 repeat_starts y 2 repeat_intervals. La tabla se vería así:
Luego, si tiene un calendario que recorre todos los días, capturando los eventos para el día en que son, la consulta se vería así:
Reemplazar
{current_timestamp}
con la marca de tiempo de Unix para la fecha actual (menos la hora, por lo que los valores de hora, minuto y segundo se establecerían en 0).¡Espero que esto ayude a alguien más también!
Almacenamiento de patrones repetitivos "complejos"
Este método es más adecuado para almacenar patrones complejos como
Event A repeats every month on the 3rd of the month starting on March 3, 2011
o
Event A repeats Friday of the 2nd week of the month starting on March 11, 2011
Recomiendo combinar esto con el sistema anterior para obtener la mayor flexibilidad. Las tablas para esto deberían gustar:
Y una mesa llamada
events_meta
así:repeat_week_im
representa la semana del mes actual, que podría estar entre 1 y 5 potencialmente.repeat_weekday
en el día de la semana, 1-7.Ahora, suponiendo que esté recorriendo los días / semanas para crear una vista mensual en su calendario, puede redactar una consulta como esta:
Esto combinado con el método anterior podría combinarse para cubrir la mayoría de los patrones de eventos recurrentes / recurrentes. Si me he perdido algo, por favor deje un comentario.
fuente
AND ( ( CASE ( 1299132000 - EM1.meta_value ) WHEN 0 THEN 1 ELSE ( 1299132000 - EM1.meta_value) END ) / EM2.meta_value ) = 1
esto se/ EM2.meta_value
coloca mal?86400
segundos en un día, porque no tiene en cuenta el horario de verano. Es más apropiado calcular estas cosas dinámicamente sobre la marcha y en su lugar almacenarinterval = daily
yinterval_count = 1
ointerval = monthly
yinterval_count = 1
.Si bien la respuesta actualmente aceptada fue de gran ayuda para mí, quería compartir algunas modificaciones útiles que simplifican las consultas y también aumentan el rendimiento.
Eventos de repetición "simples"
Para manejar eventos que se repiten a intervalos regulares, como:
o
Debería crear dos tablas, una llamada
events
así:Y una mesa llamada
events_meta
así:Al
repeat_start
ser una fecha de marca de tiempo de Unix sin tiempo (1369008000 corresponde al 20 de mayo de 2013), yrepeat_interval
una cantidad en segundos entre intervalos (604800 es de 7 días).Al recorrer cada día en el calendario, puede obtener eventos repetidos utilizando esta simple consulta:
Simplemente sustituya en la marca de tiempo Unix (1299736800) para cada fecha en su calendario.
Tenga en cuenta el uso del módulo (signo%). Este símbolo es como una división regular, pero devuelve el '' resto '' en lugar del cociente, y como tal es 0 siempre que la fecha actual sea un múltiplo exacto del repetido_intervalo desde el repetido_inicio.
Comparación de rendimiento
Esto es significativamente más rápido que la respuesta basada en "meta_keys" sugerida anteriormente, que era la siguiente:
Si ejecuta EXPLAIN esta consulta, notará que requiere el uso de un búfer de unión:
La solución con 1 combinación anterior no requiere tal búfer.
Patrones "complejos"
Puede agregar compatibilidad con tipos más complejos para admitir estos tipos de reglas de repetición:
o
Su tabla de eventos puede verse exactamente igual:
Luego, para agregar soporte para estas reglas complejas, agregue columnas para que les
events_meta
guste:Tenga en cuenta que sólo hay que especificar una
repeat_interval
o un conjunto derepeat_year
,repeat_month
,repeat_day
,repeat_week
, yrepeat_weekday
datos.Esto hace que la selección de ambos tipos simultáneamente sea muy simple. Simplemente recorra cada día y complete los valores correctos (1370563200 para el 7 de junio de 2013, y luego el año, mes, día, número de semana y día de la semana de la siguiente manera):
Esto devuelve todos los eventos que se repiten el viernes de la segunda semana, así como todos los eventos que se repiten todos los viernes, por lo que devuelve los ID de evento 1 y 2:
* Nota al margen en el SQL anterior. Utilicé los índices de lunes a viernes predeterminados de PHP Date , así que "5" para el viernes
¡Espero que esto ayude a otros tanto como la respuesta original me ayudó!
fuente
repeat_interval
columna y representarla en las columnas posteriores (es decirrepeat_year
, etc.). Para la primera fila, la situación de repetición todos los lunes después del 20 de mayo de 2013, se puede representar colocando un 1 en elrepeat_weekday
y una*
en las otras columnas.*
. Por lo tanto, para "cada mes el día 3" simplemente establecerepeat_day
en 3, el resto de losrepeat
campos en * (dejarrepeat_interval
nulo), y establece el valor de repeat_start en el código de tiempo de Unix para el 3 de marzo de 2011 como su fecha de anclaje.Mejora: reemplace la marca de tiempo con la fecha
Como una pequeña mejora a la respuesta aceptada que posteriormente fue refinada por ahoffner, es posible utilizar un formato de fecha en lugar de una marca de tiempo. Las ventajas son:
para hacer esto, cambie la base de datos
repeat_start
para que se almacene como tipo 'fecha' yrepeat_interval
ahora contenga días en lugar de segundos. es decir, 7 para una repetición de 7 días.cambiar la línea sql:
a:
Todo lo demás se mantiene igual. Simples!
fuente
Seguiría esta guía: https://github.com/bmoeskau/Extensible/blob/master/recurrence-overview.md
También asegúrese de usar el formato iCal para no reinventar la rueda y recuerde la Regla # 0: ¡NO almacene instancias de eventos recurrentes individuales como filas en su base de datos!
fuente
attendedEvent
conbaseInstanceId
yinstanceStartDate
- Ese es, por ejemplo, el evento base a partir del cual creó la vista de calendario de reglas recurrentes y use la fecha de inicio para especificar información sobre esa instancia específica. Entonces esta entidad también podría tener algo comoattendedListId
lo que conduce a otra mesa deid
,attendedUserId
Para todos los que estén interesados en esto, ahora pueden simplemente copiar y pegar para comenzar en cuestión de minutos. Tomé el consejo en los comentarios lo mejor que pude. Avísame si me falta algo.
"VERSIÓN COMPLEJA":
eventos
eventos_meta
Código SQL:
también disponible como exportación MySQL (para fácil acceso)
Código de ejemplo PHP index.php:
Código de ejemplo PHP connect.php:
También el código php está disponible aquí (para una mejor legibilidad):
index.php
y
connect.php.
Ahora configurar esto debería llevarle unos minutos. No horas :)
fuente
Si bien las soluciones propuestas funcionan, estaba tratando de implementarlas con Full Calendar y requeriría más de 90 llamadas a la base de datos para cada vista (ya que carga el mes actual, anterior y siguiente), lo cual no me entusiasmó demasiado.
Encontré una biblioteca de recursión https://github.com/tplaner/Cuando simplemente almacena las reglas en la base de datos y una consulta para extraer todas las reglas relevantes.
Espero que esto ayude a alguien más, ya que pasé tantas horas tratando de encontrar una buena solución.
Editar: esta biblioteca es para PHP
fuente
When
Tienes que almacenar todas las fechas recurrentes en la base de datos u obtener todos los eventos recurrentes y generar fechas en php no en la base de datos. Estoy en lo cierto?When
para generar todas las fechas, que se rellenan a partir de la fecha / reglas almacenadas iniciales.¿Por qué no utilizar un mecanismo similar a los trabajos de Apache cron? http://en.wikipedia.org/wiki/Cron
Para la programación de calendario, usaría valores ligeramente diferentes para "bits" para acomodar eventos de reoccurence de calendario estándar, en lugar de [día de la semana (0 - 7), mes (1 - 12), día del mes (1 - 31), hora (0 - 23), min (0 - 59)]
- Usaría algo como [Año (repetir cada N años), mes (1 - 12), día del mes (1 - 31), semana del mes (1-5), día de la semana (0 - 7) ]
Espero que esto ayude.
fuente
Desarrollé un lenguaje de programación esotérico solo para este caso. La mejor parte es que no tiene esquema y es independiente de la plataforma. Solo tiene que escribir un programa selector, para su programación, cuya sintaxis está limitada por el conjunto de reglas que se describen aquí:
https://github.com/tusharmath/sheql/wiki/Rules
Las reglas son extensibles y puede agregar cualquier tipo de personalización según el tipo de lógica de repetición que desee realizar, sin preocuparse por las migraciones de esquemas, etc.
Este es un enfoque completamente diferente y puede tener algunas desventajas propias.
fuente
Suena muy parecido a los eventos MySQL que se almacenan en las tablas del sistema. Puede mirar la estructura y descubrir qué columnas no son necesarias:
fuente
El estándar RRULE está diseñado para cumplir exactamente este requisito, es decir, guardar y comprender las recurrencias. Microsoft y Google lo usan en sus eventos de calendario. Por favor, lea este documento para más detalles. https://icalendar.org/iCalendar-RFC-5545/3-8-5-3-recurrence-rule.html
fuente
@Rogue Coder
¡Esto es genial!
Simplemente puede usar la operación de módulo (MOD o% en mysql) para simplificar su código al final:
En vez de:
Hacer:
Para llevar esto más lejos, uno podría incluir eventos que no se repiten para siempre.
Se podría agregar algo como "repeat_interval_1_end" para indicar la fecha de la última "repeat_interval_1". Sin embargo, esto hace que la consulta sea más complicada y realmente no puedo entender cómo hacer esto ...
¡Quizás alguien podría ayudar!
fuente
Los dos ejemplos que has dado son muy simples; se pueden representar como un intervalo simple (el primero son cuatro días, el segundo son 14 días). La forma en que modele esto dependerá completamente de la complejidad de sus recurrencias. Si lo que tiene arriba es realmente así de simple, almacene una fecha de inicio y la cantidad de días en el intervalo de repetición.
Sin embargo, si necesita apoyar cosas como
O
Entonces ese es un patrón mucho más complejo.
fuente