Je crée un système d'événements personnalisé, et si vous avez un événement répétitif qui ressemble à ceci:
L'événement A se répète tous les 4 jours à partir du 3 mars 2011
ou
L'événement B se répète toutes les 2 semaines le mardi à partir du 1er mars 2011
Comment puis-je stocker cela dans une base de données d'une manière qui rendrait la recherche simple. Je ne veux pas de problèmes de performances s'il y a un grand nombre d'événements, et je dois passer en revue chacun d'eux lors du rendu du calendrier.
database-design
calendar
Brandon Wamboldt
la source
la source
1299132000
est codé en dur? Que cela fera-t-il si j'ai besoin d'obtenir les dates d'occurrence et l'utilisateur pour la date de fin donnée?Réponses:
Stockage de motifs répétitifs "simples"
Pour mon calendrier basé sur PHP / MySQL, je voulais stocker les informations sur les événements récurrents / récurrents aussi efficacement que possible. Je ne voulais pas avoir un grand nombre de lignes et je voulais facilement rechercher tous les événements qui auraient lieu à une date spécifique.
La méthode ci-dessous est idéale pour stocker des informations répétitives qui se produisent à intervalles réguliers, tels que tous les jours, tous les n jours, chaque semaine, chaque mois chaque année, etc. etc. Cela inclut également les modèles de type tous les mardis et jeudis, car ils sont stockés séparément comme chaque semaine à partir d'un mardi et chaque semaine à partir d'un jeudi.
En supposant que j'ai deux tables, une appelée
events
comme ceci:Et une table appelée
events_meta
comme ceci:Avec repeat_start étant une date sans heure comme horodatage Unix, et repeat_interval un montant en secondes entre les intervalles (432000 est de 5 jours).
repeat_interval_1 va avec repeat_start de l'ID 1. Donc, si j'ai un événement qui se répète tous les mardis et tous les jeudis, le repeat_interval serait 604800 (7 jours), et il y aurait 2 repeat_starts et 2 repeat_intervals. Le tableau ressemblerait à ceci:
Ensuite, si vous avez un calendrier qui passe tous les jours, saisissant les événements du jour où il se trouve, la requête ressemblera à ceci:
Remplacement
{current_timestamp}
par l'horodatage Unix pour la date actuelle (moins l'heure, de sorte que les valeurs d'heure, de minute et de seconde soient définies sur 0).J'espère que cela aidera quelqu'un d'autre aussi!
Stockage de motifs répétitifs "complexes"
Cette méthode est mieux adaptée au stockage de motifs complexes tels que
Event A repeats every month on the 3rd of the month starting on March 3, 2011
ou
Event A repeats Friday of the 2nd week of the month starting on March 11, 2011
Je recommanderais de combiner cela avec le système ci-dessus pour plus de flexibilité. Les tableaux pour cela devraient comme:
Et une table appelée
events_meta
comme ceci:repeat_week_im
représente la semaine du mois en cours, qui pourrait être comprise entre 1 et 5 potentiellement.repeat_weekday
le jour de la semaine, 1-7.En supposant maintenant que vous parcourez les jours / semaines pour créer une vue mensuelle dans votre calendrier, vous pouvez composer une requête comme celle-ci:
Ceci combiné avec la méthode ci-dessus pourrait être combiné pour couvrir la plupart des modèles d'événements répétitifs / récurrents. Si j'ai oublié quelque chose, veuillez laisser un commentaire.
la source
AND ( ( CASE ( 1299132000 - EM1.meta_value ) WHEN 0 THEN 1 ELSE ( 1299132000 - EM1.meta_value) END ) / EM2.meta_value ) = 1
est-il/ EM2.meta_value
mal placé?86400
secondes dans une journée, car cela ne prend pas en compte l'heure d'été. Il est plus approprié de calculer ces choses dynamiquement à la volée et de stocker à la placeinterval = daily
etinterval_count = 1
ouinterval = monthly
etinterval_count = 1
.Bien que la réponse actuellement acceptée m'a été d'une grande aide, je voulais partager quelques modifications utiles qui simplifient les requêtes et augmentent également les performances.
Événements de répétition "simples"
Pour gérer des événements qui se reproduisent à intervalles réguliers, tels que:
ou
Vous devez créer deux tables, une appelée
events
comme ceci:Et une table appelée
events_meta
comme ceci:Étant
repeat_start
une date d'horodatage Unix sans heure (1369008000 correspond au 20 mai 2013), etrepeat_interval
un montant en secondes entre les intervalles (604800 est 7 jours).En parcourant chaque jour du calendrier, vous pouvez obtenir des événements répétés à l'aide de cette simple requête:
Remplacez simplement l'horodatage unix (1299736800) pour chaque date de votre calendrier.
Notez l'utilisation du modulo (signe%). Ce symbole est comme une division régulière, mais renvoie le '' reste '' au lieu du quotient, et en tant que tel est 0 chaque fois que la date actuelle est un multiple exact de repeat_interval de repeat_start.
Comparaison des performances
Ceci est beaucoup plus rapide que la réponse basée sur les "méta-clés" précédemment suggérée, qui était la suivante:
Si vous exécutez EXPLAIN cette requête, vous remarquerez qu'elle nécessitait l'utilisation d'un tampon de jointure:
La solution avec 1 jointure ci-dessus ne nécessite pas un tel tampon.
Modèles "complexes"
Vous pouvez ajouter la prise en charge de types plus complexes pour prendre en charge ces types de règles de répétition:
ou
Votre table d'événements peut avoir exactement la même apparence:
Ensuite, pour ajouter la prise en charge de ces règles complexes, ajoutez des colonnes
events_meta
comme ceci:Notez que vous simplement devez spécifier un
repeat_interval
ou un ensemble derepeat_year
,repeat_month
,repeat_day
,repeat_week
et lesrepeat_weekday
données.Cela rend la sélection des deux types simultanément très simple. Parcourez chaque jour et remplissez 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):
Cela renvoie tous les événements qui se répètent le vendredi de la 2e semaine, ainsi que tous les événements qui se répètent tous les vendredis, donc il renvoie les ID d'événement 1 et 2:
* Sidenote dans le SQL ci-dessus, j'ai utilisé les index de jour par défaut de PHP Date , donc "5" pour vendredi
J'espère que cela aide les autres autant que la réponse originale m'a aidé!
la source
repeat_interval
colonne et la représenter dans les colonnes suivantes (c.-àrepeat_year
- d. , Etc.) Pour la première ligne, la situation de répétition tous les lundis après le 20 mai 2013 peut être représentée en plaçant un 1 dans lerepeat_weekday
et un*
dans les autres colonnes.*
. Donc, pour "chaque mois le 3", vous venez de définirrepeat_day
à 3, le reste desrepeat
champs à * (laissezrepeat_interval
null), et définissez repeat_start sur le timecode unix du 3 mars 2011 pour être votre date d'ancrage.Amélioration: remplacer l'horodatage par la date
Comme une petite amélioration à la réponse acceptée qui a ensuite été affinée par ahoffner - il est possible d'utiliser un format de date plutôt qu'un horodatage. Les avantages sont:
pour ce faire, modifiez la base de données
repeat_start
à stocker en tant que type 'date' etrepeat_interval
maintenez maintenant les jours plutôt que les secondes. soit 7 pour une répétition de 7 jours.changer la ligne sql:
à:
tout le reste reste le même. Simples!
la source
Je suivrais ce guide: https://github.com/bmoeskau/Extensible/blob/master/recurrence-overview.md
Assurez-vous également que vous utilisez le format iCal afin de ne pas réinventer la roue et n'oubliez pas la règle n ° 0: Ne stockez PAS les instances d'événements récurrents individuels sous forme de lignes dans votre base de données!
la source
attendedEvent
avecbaseInstanceId
etinstanceStartDate
- C'est par exemple l'événement de base à partir duquel vous avez créé la vue de calendrier des règles récurrentes et utilisez la date de début pour spécifier des informations sur cette instance spécifique. Cette entité pourrait également avoir quelque chose commeattendedListId
qui mène à une autre table deid
,attendedUserId
Pour tous ceux qui sont intéressés par cela, il vous suffit maintenant de copier-coller pour commencer en quelques minutes. J'ai pris les conseils dans les commentaires aussi bien que possible. Faites-moi savoir si je manque quelque chose.
"VERSION COMPLEXE":
événements
events_meta
Code SQL:
également disponible en exportation MySQL (pour un accès facile)
Exemple de code PHP index.php:
Exemple de code PHP connect.php:
Le code php est également disponible ici (pour une meilleure lisibilité):
index.php
et
connect.php
Maintenant, la configuration devrait prendre quelques minutes. Pas des heures. :)
la source
Alors que les solutions proposées fonctionnent, j'essayais de l'implémenter avec le calendrier complet et cela nécessiterait plus de 90 appels de base de données pour chaque vue (car il charge le mois actuel, précédent et suivant), ce qui, je n'étais pas trop ravi.
J'ai trouvé une bibliothèque de récursivité https://github.com/tplaner/Lorsque vous stockez simplement les règles dans la base de données et une requête pour extraire toutes les règles pertinentes.
J'espère que cela aidera quelqu'un d'autre, car j'ai passé tant d'heures à essayer de trouver une bonne solution.
Edit: Cette bibliothèque est pour PHP
la source
When
Vous devez stocker toutes les dates de recurcissement dans la base de données ou obtenir tous les événements de recurcissement et générer des dates dans php no dans la base de données. Ai-je raison?When
pour générer toutes les dates - qui sont remplies à partir de la date / des règles stockées initiales.Pourquoi ne pas utiliser un mécanisme similaire aux tâches cron d'Apache? http://en.wikipedia.org/wiki/Cron
Pour le calendrier \ la planification, j'utiliserais des valeurs légèrement différentes pour les "bits" pour tenir compte des événements de réapparition du calendrier standard - au lieu de [jour de la semaine (0 - 7), mois (1 - 12), jour du mois (1 - 31), heure (0 - 23), min (0 - 59)]
- J'utiliserais quelque chose comme [Année (répéter tous les N ans), mois (1 - 12), jour du mois (1 - 31), semaine du mois (1-5), jour de la semaine (0 - 7) ]
J'espère que cela t'aides.
la source
J'ai développé un langage de programmation ésotérique juste pour ce cas. La meilleure partie à ce sujet est qu'il est sans schéma et indépendant de la plate-forme. Il vous suffit d'écrire un programme de sélection, pour votre emploi du temps, dont la syntaxe est contrainte par l'ensemble de règles décrites ici -
https://github.com/tusharmath/sheql/wiki/Rules
Les règles sont extensibles et vous pouvez ajouter n'importe quel type de personnalisation en fonction du type de logique de répétition que vous souhaitez effectuer, sans vous soucier des migrations de schéma, etc.
Il s'agit d'une approche complètement différente et qui pourrait présenter certains inconvénients.
la source
Cela ressemble beaucoup aux événements MySQL qui sont stockés dans les tables système. Vous pouvez regarder la structure et déterminer quelles colonnes ne sont pas nécessaires:
la source
La norme RRULE est conçue pour répondre exactement à cette exigence, à savoir la sauvegarde et la compréhension des récidives. Microsoft et Google l'utilisent tous les deux dans leurs événements d'agenda. Veuillez parcourir ce document pour plus de détails. https://icalendar.org/iCalendar-RFC-5545/3-8-5-3-recurrence-rule.html
la source
@Rogue Coder
C'est bien!
Vous pouvez simplement utiliser l'opération modulo (MOD ou% dans mysql) pour rendre votre code simple à la fin:
Au lieu de:
Faire:
Pour aller plus loin, on pourrait inclure des événements qui ne se reproduisent pas pour toujours.
Quelque chose comme "repeat_interval_1_end" pour indiquer la date du dernier "repeat_interval_1" pourrait être ajouté. Cependant, cela rend la requête plus compliquée et je ne peux pas vraiment comprendre comment le faire ...
Peut-être que quelqu'un pourrait aider!
la source
Les deux exemples que vous avez donnés sont très simples; ils peuvent être représentés comme un simple intervalle (le premier étant de quatre jours, le second de 14 jours). La façon dont vous modélisez cela dépendra entièrement de la complexité de vos récurrences. Si ce que vous avez ci-dessus est vraiment aussi simple que cela, enregistrez une date de début et le nombre de jours dans l'intervalle de répétition.
Si, toutefois, vous devez prendre en charge des éléments tels que
Ou
C'est un schéma beaucoup plus complexe.
la source