Buduję niestandardowy system zdarzeń, a jeśli masz powtarzające się zdarzenie, które wygląda następująco:
Wydarzenie A powtarza się co 4 dni, począwszy od 3 marca 2011 r
lub
Wydarzenie B powtarza się co 2 tygodnie we wtorek, począwszy od 1 marca 2011 r
Jak mogę przechowywać to w bazie danych w sposób, który ułatwiłby wyszukiwanie. Nie chcę problemów z wydajnością, jeśli istnieje duża liczba wydarzeń, i muszę przejrzeć każde z nich podczas renderowania kalendarza.
database-design
calendar
Brandon Wamboldt
źródło
źródło
1299132000
jest zakodowane na stałe? Co to zrobi, jeśli będę musiał uzyskać daty wystąpienia i użytkownika dla danej daty końcowej?Odpowiedzi:
Przechowywanie „prostych” powtarzalnych wzorów
W moim kalendarzu opartym na PHP / MySQL chciałem przechowywać informacje o powtarzających się / cyklicznych zdarzeniach tak efektywnie, jak to możliwe. Nie chciałem mieć dużej liczby wierszy i chciałem łatwo wyszukać wszystkie wydarzenia, które miałyby miejsce w określonym dniu.
Poniższa metoda jest świetna do przechowywania powtarzających się informacji, które pojawiają się w regularnych odstępach czasu, takich jak codziennie, co n dni, co tydzień, co miesiąc każdego roku itp. Obejmuje to również wzorce typów we wtorki i czwartki, ponieważ są one przechowywane osobno, jak co tydzień, począwszy od wtorku i co tydzień, począwszy od czwartku.
Zakładając, że mam dwie tabele, z których jedna nazywa się
events
tak:I tabela o nazwie
events_meta
tak:Powtarzanie_startu jest datą bez czasu jako uniksowego znacznika czasu, a powtarzanie_interwału w sekundach między interwałami (432000 to 5 dni).
Powtórz_interval_1 idzie z powtórzeniem_startu identyfikatora 1. Więc jeśli mam zdarzenie, które powtarza się w każdy wtorek i każdy czwartek, powtórzenie_interwału wynosiłoby 604800 (7 dni), i byłyby 2 powtórzenia_startu i 2 powtórzenia. Tabela wyglądałaby następująco:
Następnie, jeśli masz kalendarz, który przechodzi przez każdy dzień, chwytając wydarzenia z tego dnia, zapytanie wyglądałoby następująco:
Zastąpienie
{current_timestamp}
uniksowym znacznikiem czasu dla bieżącej daty (minus czas, więc godziny, minuty i sekundy zostaną ustawione na 0).Mam nadzieję, że pomoże to również komuś innemu!
Przechowywanie „złożonych” powtarzalnych wzorców
Ta metoda lepiej nadaje się do przechowywania złożonych wzorów, takich jak
Event A repeats every month on the 3rd of the month starting on March 3, 2011
lub
Event A repeats Friday of the 2nd week of the month starting on March 11, 2011
Polecam połączenie tego z powyższym systemem, aby uzyskać jak największą elastyczność. Tabele do tego powinny wyglądać następująco:
I tabela o nazwie
events_meta
tak:repeat_week_im
oznacza tydzień bieżącego miesiąca, który może wynosić od 1 do 5 potencjalnie.repeat_weekday
w dzień tygodnia, 1-7.Teraz, zakładając, że przeglądasz dni / tygodnie, aby utworzyć widok miesiąca w swoim kalendarzu, możesz napisać takie zapytanie:
To w połączeniu z powyższą metodą można połączyć, aby objąć większość powtarzających się / powtarzających się wzorców zdarzeń. Jeśli coś przeoczyłem, zostaw komentarz.
źródło
AND ( ( CASE ( 1299132000 - EM1.meta_value ) WHEN 0 THEN 1 ELSE ( 1299132000 - EM1.meta_value) END ) / EM2.meta_value ) = 1
to jest/ EM2.meta_value
źle umieszczone?86400
Sekund dziennie, ponieważ nie uwzględnia to czasu letniego. Bardziej właściwe jest obliczanie tych rzeczy dynamicznie w locie, a zamiast tego przechowywanieinterval = daily
iinterval_count = 1
lubinterval = monthly
iinterval_count = 1
.Chociaż obecnie zaakceptowana odpowiedź była dla mnie ogromną pomocą, chciałem udostępnić kilka przydatnych modyfikacji, które upraszczają zapytania i zwiększają wydajność.
„Proste” powtarzanie zdarzeń
Aby obsłużyć zdarzenia powtarzające się w regularnych odstępach czasu, takie jak:
lub
Powinieneś utworzyć dwie tabele, z których jedna nazywa się
events
tak:I tabela o nazwie
events_meta
tak:Z
repeat_start
bycia UNIX data datownik bez czasu (1369008000 odpowiada do 20 maja 2013) irepeat_interval
ilości w sekundach pomiędzy przerwami (604800 wynosi 7 dni).Pętlując każdy dzień w kalendarzu, możesz uzyskać powtarzające się zdarzenia za pomocą tego prostego zapytania:
Wystarczy zastąpić datownikiem uniksowym (1299736800) każdą datę w kalendarzu.
Zwróć uwagę na użycie modulo (znak%). Ten symbol przypomina podział zwykły, ale zwraca iloraz zamiast ilorazu i jako taki wynosi 0, ilekroć bieżąca data jest dokładną wielokrotnością przedziału powtarzania od początku_startu.
Porównanie wydajności
Jest to znacznie szybsze niż poprzednio sugerowana odpowiedź „meta_keys”, która wyglądała następująco:
Jeśli uruchomisz WYJAŚNIJ to zapytanie, zauważysz, że wymagało to użycia bufora dołączania:
Rozwiązanie z 1 złączeniem powyżej nie wymaga takiego bufora.
Wzory „złożone”
Możesz dodać obsługę bardziej złożonych typów, aby obsługiwać te typy reguł powtarzania:
lub
Tabela wydarzeń może wyglądać dokładnie tak samo:
Następnie, aby dodać obsługę tych złożonych reguł, dodaj kolumny, aby
events_meta
:Należy pamiętać, że po prostu trzeba też określić
repeat_interval
czy zestawrepeat_year
,repeat_month
,repeat_day
,repeat_week
, orazrepeat_weekday
danych.To sprawia, że wybór obu typów jednocześnie jest bardzo prosty. Wystarczy zapętlić każdy dzień i wpisać poprawne wartości (1370563200 dla 7 czerwca 2013 r., A następnie rok, miesiąc, dzień, numer tygodnia i dzień tygodnia w następujący sposób):
Zwraca wszystkie zdarzenia, które powtarzają się w piątek 2. tygodnia, a także wszystkie zdarzenia, które powtarzają się w każdy piątek, więc zwraca zarówno identyfikator zdarzenia 1, jak i 2:
* Sidenote w powyższym SQL użyłem domyślnych indeksów Dnia PHP , czyli „5” w piątek
Mam nadzieję, że to pomaga innym tak samo jak oryginalna odpowiedź pomogła mi!
źródło
repeat_interval
kolumnę i przedstawić ją w kolejnych kolumnach (tj.repeat_year
Itp.) W pierwszym rzędzie sytuację powtarzania się w każdy poniedziałek po 20 maja 2013 r. Można przedstawić, umieszczając 1 w polurepeat_weekday
oraz*
w pozostałych kolumnach.*
. Tak więc dla „co miesiąc 3-tego” ustawiłeś tylkorepeat_day
3, pozostałerepeat
pola na * (zostawrepeat_interval
null), i ustaw parametr repeat_start na kod czasowy unix dla 3 marca 2011 r. Jako datę zakotwiczenia.Ulepszenie: zastąp znacznik czasu datą
Jako niewielkie rozszerzenie przyjętej odpowiedzi, które następnie dopracował ahoffner - możliwe jest użycie formatu daty zamiast znacznika czasu. Zalety to:
Aby to zrobić, zmień DB,
repeat_start
aby był zapisany jako typ „data”, arepeat_interval
teraz przechowuj dni zamiast sekund. tj. 7 powtórzeń z 7 dni.zmień wiersz sql:
do:
Cała reszta pozostaje taka sama. Simples!
źródło
Postąpiłbym zgodnie z tym przewodnikiem: https://github.com/bmoeskau/Extensible/blob/master/recurrence-overview.md
Upewnij się także, że używasz formatu iCal, aby nie wymyślać koła na nowo, i pamiętaj Regułę 0: NIE przechowuj poszczególnych instancji zdarzeń cyklicznych jako wierszy w bazie danych!
źródło
attendedEvent
zbaseInstanceId
iinstanceStartDate
- To jest na przykład zdarzenie podstawowe, z którego utworzyłeś widok kalendarza reguł cyklicznych i użyj daty początkowej do podania informacji o tym konkretnym wystąpieniu. mieć coś takiegoattendedListId
, co prowadzi do innej tabeliid
,attendedUserId
Dla wszystkich, którzy są tym zainteresowani, teraz możesz po prostu skopiować i wkleić, aby rozpocząć w ciągu kilku minut. Skorzystałem z rad w komentarzach tak dobrze, jak mogłem. Daj mi znać, jeśli coś mi umknie.
„WERSJA KOMPLEKSOWA”:
wydarzenia
events_meta
Kod SQL:
dostępny również jako eksport MySQL (dla łatwego dostępu)
Przykładowy kod PHP index.php:
Przykładowy kod PHP connect.php:
Również kod php jest dostępny tutaj (dla lepszej czytelności):
index.php
i
connect.php
Teraz konfiguracja zajmie Ci kilka minut. Nie godziny. :)
źródło
Podczas gdy proponowane rozwiązania działają, starałem się wdrożyć z pełnym kalendarzem i wymagałoby to ponad 90 wywołań bazy danych dla każdego widoku (ponieważ ładuje bieżący, poprzedni i następny miesiąc), co nie byłem zbyt zachwycony.
Znalazłem bibliotekę rekurencyjną https://github.com/tplaner/, w której po prostu przechowujesz reguły w bazie danych i jedno zapytanie do pobrania wszystkich odpowiednich reguł.
Mam nadzieję, że pomoże to komuś innemu, ponieważ spędziłem tyle godzin, szukając dobrego rozwiązania.
Edycja: ta biblioteka jest dla PHP
źródło
When
musisz zapisać wszystkie daty odzyskania w bazie danych lub uzyskać wszystkie zdarzenia odzyskiwania i wygenerować daty w php no w bazie danych. Czy mam rację?When
do wygenerowania wszystkich dat - które są wypełniane od początkowej przechowywanej daty / reguł.Dlaczego nie skorzystać z mechanizmu podobnego do zadań Apache cron? http://en.wikipedia.org/wiki/Cron
W przypadku kalendarza \ harmonogramu użyłbym nieco innych wartości dla „bitów”, aby uwzględnić standardowe zdarzenia powtarzania kalendarza - zamiast [dzień tygodnia (0–7), miesiąc (1–12), dzień miesiąca (1–31), godzina (0–23), min (0–59)]
- Użyłbym czegoś takiego jak [Rok (powtarzaj co N lat), miesiąc (1–12), dzień miesiąca (1–31), tydzień miesiąca (1-5), dzień tygodnia (0–7) ]
Mam nadzieję że to pomoże.
źródło
Właśnie dla tego przypadku opracowałem ezoteryczny język programowania. Najlepsze w tym jest to, że nie ma schematu i jest niezależny od platformy. Musisz tylko napisać program selektora, zgodnie ze swoim harmonogramem, którego składnia jest ograniczona zestawem opisanych tutaj reguł -
https://github.com/tusharmath/sheql/wiki/Rules
Reguły są rozszerzalne i można dodawać dowolne dostosowania w oparciu o logikę powtarzania, którą chcesz wykonać, bez obawy o migrację schematu itp.
Jest to zupełnie inne podejście i może mieć swoje wady.
źródło
Brzmi bardzo podobnie do zdarzeń MySQL przechowywanych w tabelach systemowych. Możesz spojrzeć na strukturę i dowiedzieć się, które kolumny nie są potrzebne:
źródło
Standard RRULE został zbudowany właśnie dla tego wymogu, tj. Zapisywania i zrozumienia nawrotów. Zarówno Microsoft, jak i Google używają go w swoich wydarzeniach w kalendarzu. Przejrzyj ten dokument, aby uzyskać więcej informacji. https://icalendar.org/iCalendar-RFC-5545/3-8-5-3-recurrence-rule.html
źródło
@Rogue Coder
To jest świetne!
Możesz po prostu użyć operacji modulo (MOD lub% w mysql), aby na końcu uprościć kod:
Zamiast:
Zrobić:
Aby pójść dalej, można uwzględnić zdarzenia, które nie powracają na zawsze.
Można dodać coś takiego jak „repeat_interval_1_end” w celu oznaczenia daty ostatniego „repeat_interval_1”. Powoduje to jednak, że zapytanie jest bardziej skomplikowane i nie mogę naprawdę wymyślić, jak to zrobić ...
Może ktoś mógłby pomóc!
źródło
Dwa podane przykłady są bardzo proste; mogą być reprezentowane jako prosty interwał (pierwszy to cztery dni, drugi to 14 dni). Sposób modelowania będzie zależeć całkowicie od złożoności twoich nawrotów. Jeśli to, co masz powyżej, jest naprawdę takie proste, zapisz datę początkową i liczbę dni w odstępie powtarzania.
Jeśli jednak musisz wspierać takie rzeczy
Lub
To jest o wiele bardziej złożony wzór.
źródło