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:
Repeat every other day
o
Repeat every week on Tuesday
Debería crear dos tablas, una llamada events
así:
ID NAME
1 Sample Event
2 Another Event
Y una mesa llamada events_meta
así:
ID event_id repeat_start repeat_interval
1 1 1369008000 604800 -- Repeats every Monday after May 20th 2013
1 1 1369008000 604800 -- Also repeats every Friday after May 20th 2013
Al repeat_start
ser una fecha de marca de tiempo de Unix sin tiempo (1369008000 corresponde al 20 de mayo de 2013), y repeat_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:
SELECT EV.*
FROM `events` EV
RIGHT JOIN `events_meta` EM1 ON EM1.`event_id` = EV.`id`
WHERE (( 1299736800 - repeat_start) % repeat_interval = 0 )
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:
SELECT EV.*
FROM `events` EV
RIGHT JOIN `events_meta` EM1 ON EM1.`event_id` = EV.`id`
RIGHT JOIN `events_meta` EM2 ON EM2.`meta_key` = CONCAT( 'repeat_interval_', EM1.`id` )
WHERE EM1.meta_key = 'repeat_start'
AND (
( CASE ( 1299132000 - EM1.`meta_value` )
WHEN 0
THEN 1
ELSE ( 1299132000 - EM1.`meta_value` )
END
) / EM2.`meta_value`
) = 1
Si ejecuta EXPLAIN esta consulta, notará que requiere el uso de un búfer de unión:
+----+-------------+-------+--------+---------------+---------+---------+------------------+------+--------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+------------------+------+--------------------------------+
| 1 | SIMPLE | EM1 | ALL | NULL | NULL | NULL | NULL | 2 | Using where |
| 1 | SIMPLE | EV | eq_ref | PRIMARY | PRIMARY | 4 | bcs.EM1.event_id | 1 | |
| 1 | SIMPLE | EM2 | ALL | NULL | NULL | NULL | NULL | 2 | Using where; Using join buffer |
+----+-------------+-------+--------+---------------+---------+---------+------------------+------+--------------------------------+
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:
Event A repeats every month on the 3rd of the month starting on March 3, 2011
o
Event A repeats second Friday of the month starting on March 11, 2011
Su tabla de eventos puede verse exactamente igual:
ID NAME
1 Sample Event
2 Another Event
Luego, para agregar soporte para estas reglas complejas, agregue columnas para que les events_meta
guste:
ID event_id repeat_start repeat_interval repeat_year repeat_month repeat_day repeat_week repeat_weekday
1 1 1369008000 604800 NULL NULL NULL NULL NULL -- Repeats every Monday after May 20, 2013
1 1 1368144000 604800 NULL NULL NULL NULL NULL -- Repeats every Friday after May 10, 2013
2 2 1369008000 NULL 2013 * * 2 5 -- Repeats on Friday of the 2nd week in every month
Tenga en cuenta que sólo hay que especificar una repeat_interval
o un conjunto de repeat_year
, repeat_month
, repeat_day
, repeat_week
, y repeat_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):
SELECT EV.*
FROM `events` EV
RIGHT JOIN `events_meta` EM1 ON EM1.`event_id` = EV.`id`
WHERE (( 1370563200 - repeat_start) % repeat_interval = 0 )
OR (
(repeat_year = 2013 OR repeat_year = '*' )
AND
(repeat_month = 6 OR repeat_month = '*' )
AND
(repeat_day = 7 OR repeat_day = '*' )
AND
(repeat_week = 2 OR repeat_week = '*' )
AND
(repeat_weekday = 5 OR repeat_weekday = '*' )
AND repeat_start <= 1370563200
)
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:
ID NAME
1 Sample Event
2 Another Event
* 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ó!
1299132000
está codificado? ¿Qué hará esto si necesito obtener las fechas de ocurrencia y el usuario para la fecha de finalización dada?