Bien que la réponse actuellement acceptée m'ait été d'une grande aide, je voulais partager quelques modifications utiles qui simplifient les requêtes et augmentent également les performances.
"Événements répétitifs "simples
Pour gérer les événements qui se répètent à intervalles réguliers, tels que :
Repeat every other day
ou
Repeat every week on Tuesday
Vous devez créer deux tables, l'une appelée events
comme ça :
ID NAME
1 Sample Event
2 Another Event
Et une table appelée events_meta
comme ça :
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
Avec repeat_start
étant une date d'horodatage unix sans heure (1369008000 correspond au 20 mai 2013), et repeat_interval
une quantité en secondes entre les intervalles (604800 est 7 jours).
En bouclant sur chaque jour du calendrier, vous pouvez obtenir des événements répétés en utilisant cette simple requête :
SELECT EV.*
FROM `events` EV
RIGHT JOIN `events_meta` EM1 ON EM1.`event_id` = EV.`id`
WHERE (( 1299736800 - repeat_start) % repeat_interval = 0 )
Il suffit de remplacer l'horodatage unix (1299736800) pour chaque date de votre calendrier.
Notez l'utilisation du modulo (signe %). Ce symbole est comme une division ordinaire, mais renvoie le ''reste'' au lieu du quotient, et en tant que tel, il vaut 0 chaque fois que la date actuelle est un multiple exact de l'intervalle repeat_interval à partir du repeat_start.
Comparaison des performances
C'est beaucoup plus rapide que la réponse basée sur les "meta_keys" proposée précédemment, qui était la suivante :
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 vous exécutez EXPLAIN cette requête, vous constaterez qu'elle a nécessité l'utilisation d'un tampon de jointure :
+----+-------------+-------+--------+---------------+---------+---------+------------------+------+--------------------------------+
| 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 solution avec 1 jointure ci-dessus ne nécessite pas un tel tampon.
"Motifs "complexes
Vous pouvez ajouter des types plus complexes pour prendre en charge ces types de règles de répétition :
Event A repeats every month on the 3rd of the month starting on March 3, 2011
ou
Event A repeats second Friday of the month starting on March 11, 2011
Votre table d'événements peut avoir exactement le même aspect :
ID NAME
1 Sample Event
2 Another Event
Ensuite, pour ajouter le support de ces règles complexes, ajoutez des colonnes à events_meta
comme ça :
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
Notez que vous devez simplement spécifier un repeat_interval
ou un ensemble de repeat_year
, repeat_month
, repeat_day
, repeat_week
y repeat_weekday
données.
Cela rend la sélection des deux types simultanément très simple. Il suffit de parcourir chaque jour en boucle et de remplir les valeurs correctes (1370563200 pour le 7 juin 2013, puis l'année, le mois, le jour, le numéro de semaine et le jour de la semaine comme suit) :
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
)
Cela renvoie tous les événements qui se répètent le vendredi de la deuxième semaine, ainsi que tous les événements qui se répètent tous les vendredis, il renvoie donc les deux événements ID 1 et 2 :
ID NAME
1 Sample Event
2 Another Event
*Sidenote dans le SQL ci-dessus j'ai utilisé Date du PHP les index par défaut des jours de la semaine, donc "5" pour le vendredi
J'espère que cela aidera d'autres personnes autant que la réponse originale m'a aidé !
0 votes
Pouvez-vous expliquer pourquoi
1299132000
est codé en dur ? Qu'est-ce que cela va faire si j'ai besoin d'obtenir les dates d'occurrence et l'utilisateur pour la date de fin donnée ?0 votes
@Murali Boy, c'est vieux, mais je suis presque sûr que 1299132000 est censé être la date actuelle.
0 votes
@BrandonWamboldt, j'ai essayé votre idée avec SQL Server. stackoverflow.com/questions/20286332/display-next-event-date . Je veux trouver tous les éléments suivants comme version c#