Während die derzeit akzeptierte Antwort eine große Hilfe für mich war, wollte ich einige nützliche Änderungen mitteilen, die die Abfragen vereinfachen und auch die Leistung steigern.
"Einfache" Wiederholungsereignisse
So behandeln Sie Ereignisse, die in regelmäßigen Abständen wiederholt werden, wie z.
Repeat every other day
oder
Repeat every week on Tuesday
Sie sollten zwei Tabellen erstellen, eine davon heißt events
wie folgt:
ID NAME
1 Sample Event
2 Another Event
Und ein Tisch namens events_meta
so:
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
Da repeat_start
es sich um ein Unix-Zeitstempeldatum ohne Uhrzeit handelt (1369008000 entspricht dem 20. Mai 2013) und repeat_interval
einen Betrag in Sekunden zwischen den Intervallen (604800 beträgt 7 Tage).
Durch Durchlaufen jedes Tages im Kalender können Sie mit dieser einfachen Abfrage Wiederholungsereignisse abrufen:
SELECT EV.*
FROM `events` EV
RIGHT JOIN `events_meta` EM1 ON EM1.`event_id` = EV.`id`
WHERE (( 1299736800 - repeat_start) % repeat_interval = 0 )
Ersetzen Sie einfach jedes Datum in Ihrem Kalender im Unix-Zeitstempel (1299736800).
Beachten Sie die Verwendung des Modulo (% -Zeichen). Dieses Symbol ähnelt einer regulären Division, gibt jedoch den Rest anstelle des Quotienten zurück und ist daher immer dann 0, wenn das aktuelle Datum ein genaues Vielfaches des Wiederholungsintervalls aus dem Wiederholungsstart ist.
Leistungsvergleich
Dies ist erheblich schneller als die zuvor vorgeschlagene "meta_keys" -basierte Antwort, die wie folgt lautete:
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
Wenn Sie EXPLAIN für diese Abfrage ausführen, werden Sie feststellen, dass ein Verknüpfungspuffer erforderlich ist:
+----+-------------+-------+--------+---------------+---------+---------+------------------+------+--------------------------------+
| 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 |
+----+-------------+-------+--------+---------------+---------+---------+------------------+------+--------------------------------+
Die Lösung mit 1 Verknüpfung oben erfordert keinen solchen Puffer.
"Komplexe" Muster
Sie können Unterstützung für komplexere Typen hinzufügen, um diese Arten von Wiederholungsregeln zu unterstützen:
Event A repeats every month on the 3rd of the month starting on March 3, 2011
oder
Event A repeats second Friday of the month starting on March 11, 2011
Ihre Veranstaltungstabelle kann genauso aussehen:
ID NAME
1 Sample Event
2 Another Event
Um Unterstützung für diese komplexen Regeln hinzuzufügen, fügen Sie folgende Spalten hinzu events_meta
:
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
Beachten Sie, dass Sie einfach entweder müssen eine angeben repeat_interval
oder einen Satz repeat_year
, repeat_month
, repeat_day
, repeat_week
, und repeat_weekday
Daten.
Dies macht die gleichzeitige Auswahl beider Typen sehr einfach. Durchlaufen Sie einfach jeden Tag und geben Sie die richtigen Werte ein (1370563200 für den 7. Juni 2013 und dann das Jahr, den Monat, den Tag, die Wochennummer und den Wochentag wie folgt):
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
)
Dies gibt alle Ereignisse zurück, die sich am Freitag der 2. Woche wiederholen, sowie alle Ereignisse, die sich jeden Freitag wiederholen, sodass sowohl die Ereignis-ID 1 als auch 2 zurückgegeben werden:
ID NAME
1 Sample Event
2 Another Event
* Nebenbemerkung in der obigen SQL Ich habe die Standard-Wochentagsindizes von PHP Date verwendet , also "5" für Freitag
Hoffe, das hilft anderen genauso wie die ursprüngliche Antwort mir geholfen hat!
1299132000
codiert ist? Was wird dies tun, wenn ich die Vorkommensdaten und den Benutzer für das angegebene Enddatum erhalten muss?