Mentre la risposta attualmente accettata mi è stata di grande aiuto, volevo condividere alcune utili modifiche che semplificano le query e aumentano anche le prestazioni.
Eventi semplici "ripetuti"
Per gestire eventi che si ripetono a intervalli regolari, come:
Repeat every other day
o
Repeat every week on Tuesday
Dovresti creare due tabelle, una chiamata in events
questo modo:
ID NAME
1 Sample Event
2 Another Event
E un tavolo chiamato events_meta
così:
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
Con repeat_start
essendo una data timestamp unix senza tempo (1369008000 corrisponde al 20 maggio 2013), e repeat_interval
una quantità in secondi tra intervalli (604800 è di 7 giorni).
Effettuando il ciclo ogni giorno del calendario puoi ottenere eventi di ripetizione usando questa semplice query:
SELECT EV.*
FROM `events` EV
RIGHT JOIN `events_meta` EM1 ON EM1.`event_id` = EV.`id`
WHERE (( 1299736800 - repeat_start) % repeat_interval = 0 )
È sufficiente sostituire il timestamp unix (1299736800) per ciascuna data del calendario.
Nota l'uso del modulo (segno%). Questo simbolo è come una divisione regolare, ma restituisce il '' resto '' invece del quoziente, e come tale è 0 ogni volta che la data corrente è un multiplo esatto dell'intervallo di ripetizione da repeat_start.
Confronto delle prestazioni
Questo è significativamente più veloce della risposta basata su "meta_keys" precedentemente suggerita, che era la seguente:
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
Se esegui EXPLAIN questa query, noterai che è richiesto l'uso di un buffer di join:
+----+-------------+-------+--------+---------------+---------+---------+------------------+------+--------------------------------+
| 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 soluzione con 1 join sopra non richiede tale buffer.
Pattern "complessi"
È possibile aggiungere il supporto per tipi più complessi per supportare questi tipi di regole di ripetizione:
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
La tabella degli eventi può essere esattamente la stessa:
ID NAME
1 Sample Event
2 Another Event
Quindi per aggiungere il supporto per queste regole complesse aggiungi le colonne in questo events_meta
modo:
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
Si noti che è sufficiente specificare una repeat_interval
o di un insieme di repeat_year
, repeat_month
, repeat_day
, repeat_week
, e repeat_weekday
dei dati.
Questo rende la selezione di entrambi i tipi contemporaneamente molto semplice. Basta scorrere ogni giorno e inserire i valori corretti (1370563200 per il 7 giugno 2013, quindi l'anno, il mese, il giorno, il numero della settimana e il giorno della settimana come segue):
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
)
Ciò restituisce tutti gli eventi che si ripetono il venerdì della 2a settimana, nonché tutti gli eventi che si ripetono ogni venerdì, quindi restituisce sia l'ID evento 1 che 2:
ID NAME
1 Sample Event
2 Another Event
* Sidenote nell'SQL sopra ho usato gli indici dei giorni feriali predefiniti di PHP Date , quindi "5" per venerdì
Spero che questo aiuti gli altri tanto quanto la risposta originale mi ha aiutato!
1299132000
è codificato? Che cosa farà se devo ottenere le date dell'evento e l'utente per la data di fine indicata?