33 votes

Modèle de calendrier infini SQL

Je vais faire un serveur Mysql d'un calendrier basé sur le système où vous pouvez avoir un motif de répétition pour permet de dire que chaque lundi pour toujours et à jamais. Il doit aussi couvrir statique/une fois uniquement. Ce que je me demandais, est la solution qui serait la plus logique (et la meilleure) pour moi de l'utiliser. J'ai quatre méthodes qui je me demandais de choisir entre les deux.

Méthode #1

Faire une fonction qui accepte des paramètres from et to. Cette fonction serait de créer une table temporaire à la table de laquelle les importations statique existant calendrier de INSERT ... SELECT. Par la suite, il serait de lire le modèle de table et de remplir la table temporaire par le biais de la peroid basé sur from et to.

Cette solution semble intéressante du point de vue que les requêtes sera plus simple pour récupérer les données avec et il fonctionne à l'infini puisque vous pouvez simplement remplir de nouveau la table en fonction du mois où vous êtes en train de charger. Ce que je suis curieux de savoir quand cela pourrait être un lag façon de le faire ou pas.

Méthode #2

Créer et rejoindre des tendances données par le biais d'une sous-requête et JOIN avec calendrier statique.

Cela semble être plutôt gênant car les requêtes seraient beaucoup plus grand et ne serait probablement pas être bon à tous(?).

Méthode n ° 3

Bref juste INSERT modèle pour disons un an à l'avance. Ensuite, je suppose un cron job pourrait repeupler pour en faire un an à l'avance, toujours.

C'est une façon simple de le faire, mais il se sent comme beaucoup de données inutiles stockés et il ne donne pas vraiment l'infini, que je suis après.

Méthode n ° 4 (Suggéré par Veger)

Si je comprends bien, cette méthode allait chercher le motif à partir d'une autre requête et crée l'événement lors de l'exécution. Il est similaire à mes pensées au sujet de la Méthode #1 de cette façon que je considère que le modèle simple de créer plusieurs lignes.

Toutefois, si cela peut être mis en œuvre à l'extérieur de Mysql, je voudrais perdre quelques fonctionnalités de base de données qui je suis après.


J'espère que vous allez comprendre ma situation, et si vous pouviez proposer soit donné et argumenter pourquoi il est le meilleur ou donner une autre solution.

Personnellement, j'aime la Méthode #1 le plus, mais je suis curieux de savoir si c'est de lag pour repeupler le calendrier de table à chaque appel.

14voto

Jordan Patterson Points 436

J'ai construit ce genre de calendrier de l'avant. J'ai trouvé la meilleure façon de le faire est à l'approche de la manière que crons sont prévues. Ainsi, dans la base de données, en faire un terrain pour les minutes, l'heure, le jour, le mois et le jour de la semaine.

Pour un événement chaque vendredi du mois de juin et d'août à 10:00 votre entrée ressemblerait à

Minute  Hour  DayOfMonth  Month  DayOfWeek
 0       22     *          6,8       5

Vous pourriez alors avoir un champ qui l'indique comme un événement unique qui ignore cette information et il suffit d'utiliser la date de début et la durée. Pour les événements qui se répètent, qui a une fin (tous les week-end pour 3 mois), vous avez juste besoin d'ajouter un champ date de fin.

Cela vous permettra de sélectionner revenir en arrière facilement et de réduire la quantité de données qui doivent être stockées. Il simplifie vos requêtes ainsi.

Je ne pense pas qu'il existe un besoin de créer des tables temporaires. Pour sélectionner retour les événements pertinents, vous devez sélectionner par l'affichage du calendrier. Si l'affichage de votre calendrier est par le mois, vous sélectionnez ressemblerait à quelque chose comme:

SELECT Events.* 
FROM Events 
WHERE (Month LIKE '%,'.$current_month.',%' OR Month = '*') 
    AND DATE(StartDate) >= "'.date('Y-m-d', $firstDayOfCurrentMonth).'" 
    AND DATE(EndDate) <= "'.date('Y-m-d', $lastDayOfCurrentMonth).'"

Évidemment, cela doit être dans une déclaration préparée. Il suppose également que vous avez une virgule avant et après la première et la dernière valeur dans la liste séparée par des virgules de mois (c'est à dire. ,2,4,6,). Vous pouvez également créer un Month de table et une table de jointure entre les deux si vous le souhaitez. Le reste peut être analysé par php lors du rendu de votre calendrier.

Si vous affichez une vue hebdomadaire de votre calendrier, vous pouvez sélectionner dans cette façon:

SELECT Events.* 
FROM Events 
WHERE (DayOfMonth IN ('.implode(',', $days_this_week).','*') 
    AND (Month LIKE '%,'.$current_month.',%' OR Month = '*')) 
    AND DATE(StartDate) >= "'.date('Y-m-d', $firstDayOfCurrentMonth).'" 
    AND DATE(EndDate) <= "'.date('Y-m-d', $lastDayOfCurrentMonth).'"

Je n'ai pas testé ces requêtes, il y a peut-être quelques foiré de crochets ou de quelque chose. Mais que serait l'idée générale.

Donc, vous pouvez soit exécuter un select pour chaque jour que vous êtes en affichage ou vous pouvez sélectionner le dos tout pour la vue (mois, semaine, etc) et de la boucle sur les événements de chaque jour.

9voto

Explosion Pills Points 89756

J'aime Veger la solution la plus .. au lieu de remplir plusieurs lignes, vous pouvez simplement remplir le modèle. Je suggère l' crontab format .. il fonctionne si bien, de toute façon.

Vous pouvez interroger tous les modèles pour un client donné, quand ils chargent le calendrier et remplir les événements basés sur le modèle. Sauf si vous avez comme des milliers de modèles pour un seul utilisateur, ce qui ne devrait pas du tout être lent. Il devrait également être plus rapide que de stocker un grand nombre de rangée événements pendant de longues périodes. Vous devez sélectionner tous les modèles à la fois et faire un peu de prétraitement, mais une fois de plus, combien de modèles ne vous attendez par utilisateur? Même 1000 devrait être assez rapide.

4voto

Jack Points 88446

J'ai eu cette idée depuis que j'ai encore de la programmation en GW Basic ;-) quoique, à l'époque, j'ai pris l'option n ° 3 et qu'il a été. Un regard en arrière, et aussi parmi les autres réponses, ce serait ma solution actuelle.

structure de la table

start (datetime)
stop (datetime, nullable)
interval_unit ([hour, day, week, month, year?])
interval_every (1 = every <unit>, 2 every two <units>, etc.)
type ([positive (default), negative]) - will explain later

Champs optionnels:

title
duration

L' type champ détermine la façon dont le cas est traité:

  1. positif; traitement normal, elle s'affiche dans le calendrier
  2. négatif; cet événement en annule un autre (par exemple, tous les lundis, mais pas sur le 14)

helper requête

Cette requête permettra de réduire les événements à afficher:

SELECT * FROM `events`
WHERE `start` >= :start AND (`stop` IS NULL OR `stop` < :stop)

En supposant que vous vous interrogez une plage de dates seul (pas de temps de composant), la valeur de :stop devrait être un jour à l'avance de votre gamme.

Maintenant pour les différents événements que vous souhaitez gérer.

événement unique

start = '2012-06-15 09:00:00'
stop = '2012-06-15 09:00:00'
type = 'positive'

L'événement se produit une fois sur 2012-06-15 à 9h

borné à répéter l'événement

start = '2012-06-15 05:00:00'
interval_unit = 'day'
interval_every = 1
stop = '2012-06-22 05:00:00'
type = 'positive'

Des événements se produisent chaque jour à 5 heures du matin, départ sur 2012-06-15; le dernier cas est le 22

la surabondance de la répétition de l'événement

start = '2012-06-15 13:00:00'
interval_unit = 'week'
interval_every = 2
stop = null
type = 'positive'

Des événements se produisent toutes les deux semaines à 1pm, à partir 2012-06-15

répéter l'événement avec des exceptions

start = '2012-06-15 16:00:00'
interval_unit = 'week'
interval_every = 1
type = 'positive'
stop = null

start = '2012-06-22 16:00:00'
type = 'negative'
stop = '2012-06-22 16:00:00'

Événements ont lieu chaque semaine à 4h, départ sur 2012-06-22; mais pas le 22

0voto

oberron Points 2115

la meilleure solution dépend de si vous voulez faveur de conformité au standard (RFC5545) ou en travaillant exclusivement dans MySQL.

dépendent sur la flexibilité de votre règle de récurrence moteur doit être. Si vous voulez règles simples (tous les 1er du mois ou tous les mois de janvier,...), les solutions proposées ci-dessus ont été détaillées lors de la longueur.

Cependant, si vous voulez que votre application offre la compatibilité avec les normes en vigueur (RFC5545) qui implique beaucoup plus complexe de règles vous devriez jeter un oeil à ce post DONC lors de la construction d'une application de calendrier, dois-je stocker des dates ou des règles de périodicité dans ma base de données?

0voto

Hugo Delsing Points 7530

Je le ferais comme je l'ai expliqué ici. Il permettra de créer une infinité de calendrier:

PHP/MySQL: Modèle de la répétition d'événements dans une base de données, mais de requête pour les plages de dates

L'inconvénient, c'est qu'il y aura de calcul lors de la requête. Si vous avez besoin d'une haute performance de site web, le préchargement de données sera le chemin à parcourir. Vous n'avez même précharge tous les événements dans le calendrier, pour le rendre possible pour faciliter le changement des valeurs dans un seul événement. Mais il serait judicieux de stocker toutes les dates à partir de maintenant jusqu' ....

Maintenant, en utilisant les valeurs en cache-t-il faire de moins en moins l'infini, mais il va augmenter la vitesse.

Copie de awnser pour faciliter l'accès:

Je voudrais créer un tableau de pointage avec juste un col appelés id et de remplir ce tableau avec les nombres de 0 à 500. Maintenant, il nous est facile de l'utiliser pour faire des choix au lieu d'utiliser une boucle while.

Id
-------------------------------------
0
1
2
etc...

Alors j'avais stocker les événements dans une table avec Name as varchar, startdate as datetime et repeats as int

Name    | StartDate            |   Repeats
-------------------------------------
Meeting | 2012-12-10 00:00:00  |   7
Lunch   | 2012-12-10 00:00:00  |   1

Maintenant, nous pouvons utiliser le tableau de pointage pour sélectionner toutes les dates entre deux dates à l'aide:

SELECT DATE_ADD('2012-12-09 00:00:00',INTERVAL Id DAY) as showdate
FROM `tally`
WHERE (DATE_ADD('2012-12-09 00:00:00',INTERVAL Id DAY)<='2012-12-20 00:00:00')
ORDER BY Id ASC


ShowDate
-------------------------------------
2012-12-09 00:00:00
2012-12-10 00:00:00
2012-12-11 00:00:00
2012-12-12 00:00:00
2012-12-13 00:00:00
2012-12-14 00:00:00
2012-12-15 00:00:00
2012-12-16 00:00:00
2012-12-17 00:00:00
2012-12-18 00:00:00
2012-12-19 00:00:00
2012-12-20 00:00:00

Ensuite, nous nous joignons à la présente sur la table des événements pour calculer la différence entre la date de début et la showdate. Nous avons divisé les résultats de cette par l' repeats colonne et si le reste est 0, nous avons de match.

Le tout combiné devient:

SELECT E.Id, E.Name, E.StartDate, E.Repeats, A.ShowDate, DATEDIFF(E.StartDate, A.ShowDate) AS diff
FROM events AS E, (
    SELECT DATE_ADD('2012-12-09 00:00:00',INTERVAL Id DAY) as showdate
    FROM `tally`
    WHERE (DATE_ADD('2012-12-09 00:00:00',INTERVAL Id DAY)<='2012-12-20 00:00:00')
    ORDER BY Id ASC
) a
WHERE MOD(DATEDIFF(E.StartDate, A.ShowDate), E.Repeats)=0
AND A.ShowDate>=E.StartDate

Qui résultats dans

Id  | Name       |StartDate             | Repeats   | ShowDate              | diff
---------------------------------------------------------------------------------
1   | Meeting    | 2012-12-10 00:00:00  | 7         | 2012-12-10 00:00:00   | 0
2   | Lunch      | 2012-12-10 00:00:00  | 1         | 2012-12-10 00:00:00   | 0
2   | Lunch      | 2012-12-10 00:00:00  | 1         | 2012-12-11 00:00:00   | -1
2   | Lunch      | 2012-12-10 00:00:00  | 1         | 2012-12-12 00:00:00   | -2
2   | Lunch      | 2012-12-10 00:00:00  | 1         | 2012-12-13 00:00:00   | -3
2   | Lunch      | 2012-12-10 00:00:00  | 1         | 2012-12-14 00:00:00   | -4
2   | Lunch      | 2012-12-10 00:00:00  | 1         | 2012-12-15 00:00:00   | -5
2   | Lunch      | 2012-12-10 00:00:00  | 1         | 2012-12-16 00:00:00   | -6
1   | Meeting    | 2012-12-10 00:00:00  | 7         | 2012-12-17 00:00:00   | -7
2   | Lunch      | 2012-12-10 00:00:00  | 1         | 2012-12-17 00:00:00   | -7
2   | Lunch      | 2012-12-10 00:00:00  | 1         | 2012-12-18 00:00:00   | -8
2   | Lunch      | 2012-12-10 00:00:00  | 1         | 2012-12-19 00:00:00   | -9
2   | Lunch      | 2012-12-10 00:00:00  | 1         | 2012-12-20 00:00:00   | -10

Maintenant, vous pouvez (et devez!) d'accélérer les choses. Par exemple, directement à l'enregistrement des dates dans une table de sorte que vous pouvez simplement sélectionner toutes les dates directement au lieu d'utiliser un tableau de pointage avec dateadd. Chaque chose que vous pouvez mettre en cache et n'avez pas à calculer de nouveau, est bon.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X