Database
 sql >> Database >  >> RDS >> Database

Ancora e ancora! Gestione di eventi ricorrenti in un modello di dati

Un evento ricorrente, per definizione, è un evento che ricorre ad un intervallo; è anche chiamato evento periodico. Esistono molte applicazioni che consentono ai propri utenti di impostare eventi ricorrenti. In che modo un sistema di database gestisce gli eventi ricorrenti? In questo articolo esploreremo un modo in cui vengono gestiti.

La ricorrenza non è facile da gestire per le applicazioni. Può diventare un compito da uragano, soprattutto quando si tratta di coprire ogni possibile scenario ricorrente, inclusa la creazione di eventi bisettimanali o trimestrali o la possibilità di riprogrammare tutte le istanze di eventi futuri.

Due modi per gestire gli eventi ricorrenti

Posso pensare ad almeno due modi per gestire le attività periodiche in un modello di dati. Prima di discuterne, esaminiamo rapidamente i requisiti di questo compito. In poche parole, una gestione efficace significa:

  • Gli utenti possono creare eventi regolari e ricorrenti.
  • È possibile creare eventi giornalieri, settimanali, bisettimanali, mensili, trimestrali, biennali e annuali senza limitazioni di data di fine.
  • Gli utenti possono riprogrammare o annullare un'istanza di un evento o tutte le istanze future di un evento.

Considerando questi parametri, vengono in mente due modi per gestire gli eventi ricorrenti nel modello di dati. Li chiameremo il modo ingenuo e il modo esperto.

Il modo ingenuo: Memorizzazione di tutte le possibili istanze ricorrenti di un evento come righe separate in una tabella. In questa soluzione, abbiamo bisogno di una sola tabella, ovvero event . Questa tabella ha colonne come event_title , start_date , end_date , is_full_day_event , ecc. Il start_date e end_date le colonne sono tipi di dati timestamp; in questo modo possono ospitare eventi che non durano tutto il giorno.

I professionisti: Questo è un approccio piuttosto semplice e il più semplice da implementare.

I contro: Il modo ingenuo ha alcuni aspetti negativi significativi, tra cui:

  • La necessità di memorizzare tutte le possibili istanze di un evento. Se stai prendendo in considerazione le esigenze di una vasta base di utenti, è necessario un grosso pezzo di spazio. Tuttavia, lo spazio è piuttosto economico, quindi questo punto non ha un grande impatto.
  • Un processo di aggiornamento molto disordinato. Supponiamo che un evento venga riprogrammato. In tal caso, qualcuno deve aggiornarne tutte le istanze. È necessario eseguire un numero enorme di operazioni DML durante la riprogrammazione, il che crea un impatto negativo sulle prestazioni dell'applicazione.
  • Gestione delle eccezioni. Tutte le eccezioni devono essere gestite con garbo, soprattutto se devi tornare indietro e modificare l'appuntamento originale dopo aver fatto un'eccezione. Si supponga, ad esempio, di spostare in avanti di un giorno la terza istanza di un evento ricorrente. Cosa succede se successivamente modifichi l'ora dell'evento originale? Reinserisci un altro evento nel giorno originale e lasci quello che hai anticipato? Scollegare l'eccezione? Provare a cambiarlo in modo appropriato?
  • Il modo degli esperti: Memorizzazione di un modello ricorrente e generazione di istanze di eventi passati e futuri in modo programmatico. Questa soluzione affronta gli aspetti negativi della soluzione ingenua. Spiegheremo in dettaglio la soluzione per esperti in questo articolo.

    Il modello proposto




    Creazione di eventi

    Tutti gli eventi programmati, indipendentemente dalla loro natura regolare o ricorrente, vengono registrati nell'event tavolo. Non tutti gli eventi sono eventi ricorrenti, quindi avremo bisogno di una colonna flag, is_recurring , in questa tabella per specificare in modo esplicito gli eventi ricorrenti. Il event_title e event_description le colonne memorizzano l'argomento e un breve riepilogo degli eventi. Le descrizioni degli eventi sono facoltative, motivo per cui questa colonna è nullable.

    Come suggeriscono i loro nomi, la start_date e end_date le colonne mantengono le date di inizio e fine degli eventi. Nel caso di eventi regolari, queste colonne memorizzano le date effettive di inizio e fine. Tuttavia, memorizzano anche le date della prima e dell'ultima occorrenza di eventi periodici. Manterremo il end_date colonna come nullable, poiché gli utenti possono configurare eventi ricorrenti senza data di fine. In questo caso, le occorrenze future fino a una data di fine ipotetica (ad esempio per un anno) verrebbero visualizzate nell'interfaccia utente.

    Il is_full_date_event colonna indica se un evento è un evento di un'intera giornata. Nel caso di un evento di un'intera giornata, il start_time e end_time le colonne sarebbero nulle; questo è il motivo per mantenere entrambe queste colonne annullabili.

    Il created_by e created_date le colonne memorizzano l'utente che ha creato un evento e la data di creazione dell'evento.

    Poi c'è il parent_event_id colonna. Questo gioca un ruolo importante nel nostro modello di dati. Spiegherò il suo significato più avanti.

    Gestione delle ricorrenze

    Ora arriviamo direttamente all'affermazione del problema principale:cosa succede se viene creato un evento ricorrente nell'event tabella – ovvero il is_recurring il flag per l'evento è "Y"?

    Come spiegato in precedenza, memorizzeremo un modello ricorrente per gli eventi in modo da poter costruire tutte le sue occorrenze future. Iniziamo creando il recurring_pattern tavolo. Questa tabella ha le seguenti colonne:

    • Event_id – Questa colonna è referenziata dall'event tabella e funge da chiave primaria in questa tabella. Mostra la relazione identificativa tra event e recurring_pattern tavoli. Questa colonna assicurerà inoltre che vi sia un massimo di un pattern ricorrente esistente per ogni evento.
    • Recurring_type_id – Questa colonna indica il tipo di ricorrenza, sia giornaliera, settimanale, mensile o annuale.
    • Max_num_of_occurrances – Ci sono momenti in cui non conosciamo la data di fine esatta di un evento ma sappiamo quante occorrenze (riunioni) sono necessarie per completarlo. Questa colonna memorizza un numero arbitrario che definisce la fine logica di un evento.
    • Separation_count – Ci si potrebbe chiedere come si possa configurare un evento bisettimanale o biennale se sono presenti solo quattro possibili valori di tipo di ricorrenza (giornaliero, settimanale, mensile, annuale). La risposta è il separation_count colonna. Questa colonna indica l'intervallo (in giorni, settimane o mesi) prima che sia consentita l'istanza dell'evento successiva. Ad esempio, se è necessario configurare un evento a settimane alterne, separation_count ="1" per soddisfare questo requisito. Il valore predefinito per questa colonna è "0".

    Consideriamo il significato delle restanti colonne in termini di diversi tipi di ricorrenze.

    Ricorrenza quotidiana

    Abbiamo davvero bisogno di catturare uno schema per un evento ricorrente quotidiano? No, perché tutti i dettagli necessari per generare un pattern di ricorrenza giornaliera sono già registrati nell'event tabella.

    L'unico scenario che richiede uno schema è quando gli eventi sono programmati per giorni alterni o ogni X numero di giorni. In questo caso, il separation_count la colonna ci aiuterà a capire il modello di ricorrenza e a derivare ulteriori istanze.

    Ricorrenza settimanale

    Abbiamo bisogno di una sola colonna aggiuntiva, day_of_week , per memorizzare il giorno della settimana in cui si svolgerà questo evento. Supponendo che lunedì sia il primo giorno della settimana e la domenica sia l'ultimo, i valori possibili sarebbero 1,2,3,4,5,6 e 7. Le modifiche appropriate al codice che genera le occorrenze di singoli eventi devono essere apportate secondo necessità. Tutte le colonne rimanenti sarebbero nulle per gli eventi settimanali.

    Prendiamo un tipo classico di evento settimanale:il bisettimanale. In questo caso, diremo che accade ogni settimana alternata di martedì, il secondo giorno della settimana. Quindi:

    • Il recurring_type_id sarebbe “settimanale”.
    • Il separation_count sarebbe “1”.
    • Il day_of_week sarebbe "2".

    Ricorrenza mensile

    Oltre a day_of_week , sono necessarie altre due colonne per soddisfare qualsiasi scenario di ricorrenza mensile. In breve, queste colonne sono:

    • Week_of_month – Questa colonna è per gli eventi che sono programmati per una determinata settimana del mese, ovvero il primo, il secondo, l'ultimo, il penultimo, ecc. Possiamo memorizzare questi valori come 1,2,3, 4,.. (contando da l'inizio del mese) o -1,-2,-3,... (contando dalla fine del mese).
    • Day_of_month – Ci sono casi in cui un evento è programmato in un particolare giorno del mese, diciamo il 25. Questa colonna soddisfa questo requisito. Come week_of_month , può essere popolato con numeri positivi ( “7” per il 7° giorno da inizio mese) o con numeri negativi ( “-7” per il settimo giorno da fine mese).

    Consideriamo ora un esempio più complicato:un evento trimestrale. Si supponga che una società pianifichi un evento di proiezione dei risultati trimestrali per l'11 giorno del primo mese di ogni trimestre (di solito gennaio, aprile, luglio e ottobre). Quindi in questo caso:

    • Il recurring_type_id sarebbe “mensile”.
    • Il separation_count sarebbe "2".
    • Il day_of_month sarebbe “11”.
    • Tutte le colonne rimanenti sarebbero nulle.

    Nell'esempio sopra, presupponiamo che l'utente stia creando la proiezione del risultato trimestrale a gennaio. Tieni presente che questa logica di separazione inizierà a contare dal mese, dalla settimana o dal giorno in cui viene creato l'evento.

    Su righe simili, gli eventi semestrali possono essere registrati come eventi mensili con un separation_count di “5”.

    Ricorrenza annuale

    La ricorrenza annuale è abbastanza semplice. Abbiamo colonne per determinati giorni della settimana e del mese, quindi è necessaria solo una colonna aggiuntiva per il mese dell'anno. Abbiamo chiamato questa colonna month_of_year .

    Gestione delle eccezioni di eventi ricorrenti

    Veniamo ora alle eccezioni. Cosa succede se una particolare istanza di un evento ricorrente viene annullata o riprogrammata? Tutte queste istanze vengono registrate separatamente in event_instance_exception tavolo.

    Diamo un'occhiata a due colonne, Is_rescheduled e is_cancelled . Queste colonne indicano se questa istanza viene riprogrammata a una data/ora successiva o annullata del tutto. Perché ho due colonne separate per questo? Bene, pensa solo agli eventi che sono stati prima riprogrammati e poi completamente cancellati. Questo accade e abbiamo un modo per registrarlo con queste colonne.

    A parte queste due colonne, tutte le colonne rimanenti funzionano come nell'event tabella.

    Perché collegare due eventi tramite parent_event_id ?

    Esistono applicazioni che consentono agli utenti di riprogrammare tutte le istanze future di un evento ricorrente. In questi casi, abbiamo due opzioni. Possiamo archiviare tutte le istanze future in event_instance_exception (suggerimento:soluzione non accettabile). Oppure possiamo creare un nuovo evento con nuovi parametri di data/ora nell'event tabella e collegarlo al suo evento precedente (l'evento padre) tramite id_parent_event colonna.

    Con questa soluzione, possiamo ottenere tutte le occorrenze passate di un evento, anche quando il suo schema di ricorrenza è stato modificato.

    Come migliorare la gestione degli eventi ricorrenti?

    Ci sono alcune aree più complesse intorno agli eventi ricorrenti che non abbiamo discusso. Eccone due:

    • Eventi che si verificano nei giorni festivi. Quando un caso particolare di un evento si verifica in un giorno festivo, dovrebbe essere spostato automaticamente al giorno lavorativo immediatamente successivo al giorno festivo? O dovrebbe essere cancellato automaticamente? In quali circostanze si applicherebbero una di queste due?
    • Conflitti tra eventi. Cosa succede se determinati eventi (che si escludono a vicenda) cadono lo stesso giorno?

    Quali cambiamenti dobbiamo apportare per sviluppare queste capacità? Per favore, dicci le tue opinioni nella sezione commenti.