Ich baue ein benutzerdefiniertes Ereignissystem auf, und wenn Sie ein sich wiederholendes Ereignis haben, das so aussieht:
Ereignis A wird ab dem 3. März 2011 alle 4 Tage wiederholt
oder
Event B wird ab dem 1. März 2011 alle 2 Wochen am Dienstag wiederholt
Wie kann ich das in einer Datenbank so speichern, dass die Suche einfacher wird? Ich möchte keine Leistungsprobleme, wenn es eine große Anzahl von Ereignissen gibt, und ich muss jedes einzelne beim Rendern des Kalenders durchgehen.
database-design
calendar
Brandon Wamboldt
quelle
quelle
1299132000
codiert ist? Was wird dies tun, wenn ich die Vorkommensdaten und den Benutzer für das angegebene Enddatum erhalten muss?Antworten:
Speichern von "einfachen" sich wiederholenden Mustern
Für meinen PHP / MySQL-basierten Kalender wollte ich Informationen zu sich wiederholenden / wiederkehrenden Ereignissen so effizient wie möglich speichern. Ich wollte nicht viele Zeilen haben und ich wollte einfach alle Ereignisse nachschlagen, die an einem bestimmten Datum stattfinden würden.
Die folgende Methode eignet sich hervorragend zum Speichern sich wiederholender Informationen, die in regelmäßigen Abständen auftreten, z. B. jeden Tag, alle n Tage, jede Woche, jeden Monat, jedes Jahr usw. usw. Dies schließt auch Muster vom Typ Dienstag und Donnerstag ein, da sie gespeichert werden getrennt wie jede Woche ab Dienstag und jede Woche ab Donnerstag.
Angenommen, ich habe zwei Tabellen, von denen eine so heißt
events
:Und ein Tisch namens
events_meta
so:Bei repeat_start handelt es sich um ein Datum ohne Uhrzeit als Unix-Zeitstempel, und bei repeat_interval um einen Betrag in Sekunden zwischen den Intervallen (432000 beträgt 5 Tage).
repeat_interval_1 gehört zu repeat_start der ID 1. Wenn ich also ein Ereignis habe, das sich jeden Dienstag und jeden Donnerstag wiederholt, wäre das repeat_interval 604800 (7 Tage) und es gäbe 2 repeat_starts und 2 repeat_intervals. Der Tisch würde so aussehen:
Wenn Sie dann einen Kalender haben, der jeden Tag durchläuft und die Ereignisse für den Tag abruft, an dem er sich befindet, sieht die Abfrage folgendermaßen aus:
Ersetzen
{current_timestamp}
durch den Unix-Zeitstempel für das aktuelle Datum (abzüglich der Uhrzeit, sodass die Werte für Stunde, Minute und Sekunde auf 0 gesetzt werden).Hoffentlich hilft das auch jemand anderem!
Speichern "komplexer" sich wiederholender Muster
Diese Methode eignet sich besser zum Speichern komplexer Muster wie z
Event A repeats every month on the 3rd of the month starting on March 3, 2011
oder
Event A repeats Friday of the 2nd week of the month starting on March 11, 2011
Ich würde empfehlen, dies mit dem oben genannten System zu kombinieren, um die größtmögliche Flexibilität zu erzielen. Die Tabellen dafür sollten wie folgt aussehen:
Und ein Tisch namens
events_meta
so:repeat_week_im
stellt die Woche des aktuellen Monats dar, die möglicherweise zwischen 1 und 5 liegen kann.repeat_weekday
am Wochentag 1-7.Angenommen, Sie durchlaufen die Tage / Wochen, um eine Monatsansicht in Ihrem Kalender zu erstellen, können Sie eine Abfrage wie folgt erstellen:
Dies kann in Kombination mit dem obigen Verfahren kombiniert werden, um die meisten sich wiederholenden / wiederkehrenden Ereignismuster abzudecken. Wenn ich etwas verpasst habe, hinterlasse bitte einen Kommentar.
quelle
AND ( ( CASE ( 1299132000 - EM1.meta_value ) WHEN 0 THEN 1 ELSE ( 1299132000 - EM1.meta_value) END ) / EM2.meta_value ) = 1
ist/ EM2.meta_value
das falsch platziert?86400
Sekunden an einem Tag, da die Sommerzeit nicht berücksichtigt wird. Es ist besser, diese Dinge dynamisch im laufenden Betrieb zu berechnen und stattdesseninterval = daily
undinterval_count = 1
oderinterval = monthly
und zu speicherninterval_count = 1
.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.
oder
Sie sollten zwei Tabellen erstellen, eine davon heißt
events
wie folgt:Und ein Tisch namens
events_meta
so:Da
repeat_start
es sich um ein Unix-Zeitstempeldatum ohne Uhrzeit handelt (1369008000 entspricht dem 20. Mai 2013) undrepeat_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:
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:
Wenn Sie EXPLAIN für diese Abfrage ausführen, werden Sie feststellen, dass ein Verknüpfungspuffer erforderlich ist:
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:
oder
Ihre Veranstaltungstabelle kann genauso aussehen:
Um Unterstützung für diese komplexen Regeln hinzuzufügen, fügen Sie folgende Spalten hinzu
events_meta
:Beachten Sie, dass Sie einfach entweder müssen eine angeben
repeat_interval
oder einen Satzrepeat_year
,repeat_month
,repeat_day
,repeat_week
, undrepeat_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):
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:
* 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!
quelle
repeat_interval
Spalte entfernt und in den nachfolgenden Spalten (z. B.repeat_year
usw.) dargestellt werden. In der ersten Zeile kann die Situation der Wiederholung jeden Montag nach dem 20. Mai 2013 durch Platzieren einer 1 in der dargestellt werdenrepeat_weekday
und ein*
in den anderen Spalten.*
. Für "jeden Monat am 3." setzen Sie einfachrepeat_day
3, die restlichenrepeat
Felder auf * (lassen Sierepeat_interval
null) und setzen den repeat_start auf den Unix-Timecode für den 3. März 2011 als Ankerdatum.Verbesserung: Zeitstempel durch Datum ersetzen
Als kleine Erweiterung der akzeptierten Antwort, die später von ahoffner verfeinert wurde, ist es möglich, ein Datumsformat anstelle eines Zeitstempels zu verwenden. Die Vorteile sind:
Ändern Sie dazu die DB
repeat_start
, die als Typ 'Datum' gespeichert werden soll, undrepeat_interval
halten Sie jetzt Tage statt Sekunden. dh 7 für eine Wiederholung von 7 Tagen.Ändern Sie die SQL-Zeile:
zu:
alles andere bleibt gleich. Simples!
quelle
Ich würde dieser Anleitung folgen: https://github.com/bmoeskau/Extensible/blob/master/recurrence-overview.md
Stellen Sie außerdem sicher, dass Sie das iCal-Format verwenden, um das Rad nicht neu zu erfinden, und denken Sie an Regel 0: Speichern Sie einzelne wiederkehrende Ereignisinstanzen NICHT als Zeilen in Ihrer Datenbank!
quelle
attendedEvent
mitbaseInstanceId
undinstanceStartDate
- Das ist zum Beispiel das Basisereignis, aus dem Sie die Kalenderansicht für wiederkehrende Regeln erstellt haben und das Startdatum verwenden, um Informationen zu dieser bestimmten Instanz anzugeben. Dann könnte diese Entität auch habe so etwas wieattendedListId
was zu einem anderen Tisch führtid
,attendedUserId
Für alle, die daran interessiert sind, können Sie jetzt einfach kopieren und einfügen, um innerhalb von Minuten loszulegen. Ich habe den Rat in den Kommentaren so gut ich konnte befolgt. Lassen Sie mich wissen, wenn mir etwas fehlt.
"KOMPLEXE VERSION":
Veranstaltungen
events_meta
SQL-Code:
auch als MySQL-Export verfügbar (für einfachen Zugriff)
PHP-Beispielcode index.php:
PHP-Beispielcode connect.php:
Auch der PHP-Code ist hier verfügbar (zur besseren Lesbarkeit):
index.php
und
connect.php Das
Einrichten sollte nun Minuten dauern. Keine Stunden. :) :)
quelle
Während die vorgeschlagenen Lösungen funktionieren, habe ich versucht, sie mit dem vollständigen Kalender zu implementieren, und es würden über 90 Datenbankaufrufe für jede Ansicht erforderlich sein (da sie den aktuellen, vorherigen und nächsten Monat lädt), worüber ich nicht allzu begeistert war.
Ich habe eine Rekursionsbibliothek https://github.com/tplaner/ gefunden, in der Sie einfach die Regeln in der Datenbank speichern und eine Abfrage, um alle relevanten Regeln abzurufen.
Hoffentlich hilft das jemand anderem, da ich so viele Stunden damit verbracht habe, eine gute Lösung zu finden.
Bearbeiten: Diese Bibliothek ist für PHP
quelle
When
Sie alle wiederkehrenden Daten in der Datenbank speichern oder alle wiederkehrenden Ereignisse abrufen und Daten in PHP-Nr. In der Datenbank generieren müssen. Habe ich recht?When
, um alle Daten zu generieren, die aus dem anfänglich gespeicherten Datum / den Regeln gespeichert werden.Warum nicht einen Mechanismus verwenden, der Apache-Cron-Jobs ähnelt? http://en.wikipedia.org/wiki/Cron
Für Kalender \ Zeitplanung würde ich leicht unterschiedliche Werte für "Bits" verwenden, um Standardereignisse für das Wiederauftreten des Kalenders zu berücksichtigen - anstelle von [Wochentag (0 - 7), Monat (1 - 12), Tag des Monats (1 - 31), Stunde (0 - 23), min (0 - 59)]
- Ich würde so etwas wie [Jahr (alle N Jahre wiederholen), Monat (1 - 12), Tag des Monats (1 - 31), Woche des Monats (1-5), Tag der Woche (0 - 7) verwenden. ]]
Hoffe das hilft.
quelle
Ich habe nur für diesen Fall eine esoterische Programmiersprache entwickelt. Das Beste daran ist, dass es schemafrei und plattformunabhängig ist. Sie müssen lediglich ein Auswahlprogramm für Ihren Zeitplan schreiben, dessen Syntax durch die hier beschriebenen Regeln eingeschränkt wird.
https://github.com/tusharmath/sheql/wiki/Rules
Die Regeln sind erweiterbar und Sie können jede Art von Anpassung hinzufügen, die auf der Art der Wiederholungslogik basiert, die Sie ausführen möchten, ohne sich um Schemamigrationen usw. kümmern zu müssen.
Dies ist ein völlig anderer Ansatz und kann einige eigene Nachteile haben.
quelle
Klingt sehr nach MySQL-Ereignissen, die in Systemtabellen gespeichert sind. Sie können sich die Struktur ansehen und herausfinden, welche Spalten nicht benötigt werden:
quelle
Der RRULE-Standard wurde genau für diese Anforderung entwickelt, dh das Speichern und Verstehen von Wiederholungen. Microsoft und Google verwenden es beide in ihren Kalenderereignissen. Bitte lesen Sie dieses Dokument für weitere Details. https://icalendar.org/iCalendar-RFC-5545/3-8-5-3-recurrence-rule.html
quelle
@ Rogue Coder
Das ist toll!
Sie können einfach die Modulo-Operation (MOD oder% in MySQL) verwenden, um Ihren Code am Ende einfach zu gestalten:
Anstatt:
Machen:
Um dies weiter zu führen, könnte man Ereignisse einschließen, die nicht für immer wiederkehren.
Etwas wie "repeat_interval_1_end", um das Datum des letzten "repeat_interval_1" anzugeben, könnte hinzugefügt werden. Dies macht die Abfrage jedoch komplizierter und ich kann nicht wirklich herausfinden, wie das geht ...
Vielleicht könnte jemand helfen!
quelle
Die beiden Beispiele, die Sie gegeben haben, sind sehr einfach. Sie können als einfaches Intervall dargestellt werden (das erste ist vier Tage, das zweite 14 Tage). Wie Sie dies modellieren, hängt ganz von der Komplexität Ihrer Wiederholungen ab. Wenn das, was Sie oben haben, wirklich so einfach ist, speichern Sie ein Startdatum und die Anzahl der Tage im Wiederholungsintervall.
Wenn Sie jedoch Dinge wie unterstützen müssen
Oder
Dann ist das ein viel komplexeres Muster.
quelle