2013-01-19 11 views
5

Sto scrivendo una piccola applicazione che gestisce le attività per le persone. Molto semplice, ma l'area su cui sono bloccato, per quanto riguarda il design del tavolo, è il caso di un'attività ricorrente, che può essere una tantum, giornaliera, settimanale o mensile. Se settimanale, è in un giorno specifico, settimanale. Mensile è un giorno specifico.Opzione di progettazione per "attività ricorrenti"

Ho una tabella delle attività e un ricorrente_idip_id, e ho intenzione di gestire le attività ricorrenti nel codice, ma è il modo ideale? L'altro modo è quello di inserire tutte le attività quando l'attività viene creata, per ogni ora dell'evento. Ma neanche questo sembra giusto.

Qualcuno può consigliare un progetto e come gestirlo in modo efficiente ed efficiente?

sto usando SQL Server 2008 R2

+0

Mensile - se si imposta un numero di giorno non è possibile gestire 31 per alcuni mesi e anche 30 e 29 per febbraio. Hai bisogno di una logica più complessa qui? – Serg

+0

In questi casi, la mia logica sarebbe che se l'attività è impostata per il 31st e il mese ha 30, 29 o 28 giorni, utilizzare l'ultimo giorno disponibile di THAT month. – Craig

+0

@Craig è stata la risposta abbastanza buona per la taglia? – Lance

risposta

10

vorrei creare una tabella compito di inserire i miei compiti in.

taskTable 
|taskID |Freq |runAt  | 
------------------------------- 
|1  |daily |1   | 
|2  |daily |0   | 
|3  |weekly |5   | 
|4  |weekly |1   | 
|5  |monthly|15   | 
|6  |monthly|1   | 
|7  |once |2013-7-4 | 

runat per quotidiani non viene mai considerata in modo che non importa quale valore immesso.

runAt per settimanale elementi è il giorno della settimana in cui deve essere eseguita l'attività.

runat per mothly è il giorno del mese che il compito è quello di eseguire (operazioni di fine mese Io di solito eseguito il primo poiché non è di risparmiare il fastidio di trattare con quale giorno del mese si conclude il anche se si potrebbe usare questo per capirlo

lastDayOfMonth = datePart(d,dateadd(s,-1,dateadd(mm, datediff(m,0,getdate())+1,0))) 

runat per volta è il giorno stesso il compito è quello di eseguire.

Poi mi piacerebbe creare un compito da eseguire ogni giorno per vedere quello che doveva essere eseguito.

select taskID 
from taskTable 
where (freq = 'once' and runAt = convert(varchar(10),getDate(),21)) 
    or freq = 'daily' 
    or (freq = 'weekly' and runAt = datePart(dw,getDate())) 
    or (freq = 'monthly' and runAt = datePart(d,getDate()) 

Questa query mi fornisce tutte le attività per tutte le attività che è necessario eseguire.

Non so se questo è ciò che stavi cercando, ma spero che troverai qualcosa di utile in esso.

+0

Scommetto che dovresti usare datepart (giorno della settimana, getDate()) quando freq è 'settimanale' .. o ti mancherà qualcosa tra qualche settimana ..;) ma nel complesso è una bella soluzione – Frederic

+0

grazie @Frederic l'ho aggiornato – Lance

+0

Questa soluzione funziona, ma solo se si sta bene con le attività/promemoria/notifiche in esecuzione alla stessa ora del giorno, o ogni volta che si decide di eseguire l'attività di attivazione. Se si desidera la flessibilità per consentire all'utente per specificare l'ora del giorno, è necessario risolvere il problema più come suggerito da Attila. La soluzione ottimale è probabilmente un ibrido di questo e la soluzione di tabella cron, poiché la soluzione di tabella cron non è riuscita a tenere conto di una tantum. –

1

devo fare una cosa molto simile:

_id 
    interval_type 
    time 
    day 
    next 

Il campo day rappresenta il giorno entro l'intervallo, che è nullo per one-shot e tutti i giorni. Il campo next nella tabella viene utilizzato per identificare quando l'attività deve essere eseguita successivamente. Questo è necessario per quei casi in cui il dispositivo è spento quando l'attività deve essere eseguita. Hai solo bisogno di decidere come gestire uno o più intervalli mancati.

1

dovrei voler utilizzare una data di riferimento come una tabella come questa

taskid  date_reference Freq   distance 
----------- -------------- --------------- ----------- 
1   2011-01-01  daily   NULL 
2   2011-01-17  monthly   NULL 
3   2013-01-17  weekly   NULL 
4   2013-01-24  once   NULL 
5   2011-01-01  monthly   NULL 
6   2011-01-01  monthly   NULL 
7   2011-01-01  before_eomonth 5 
8   2013-01-01  loop_day  4 
9   2013-01-01  loop_month  4 

in modo da poter controllare il periodo in molti modi ...

tradizionale settimanale, giornaliera, mensile e una volta . come la soluzione della lancia ..

ma si avrebbe diversi modi, come

ogni 4 giorni

ogni 4 mesi

o 5 giorni alla fine del mese,

o alla fine del mese

dovrebbe considerare di includere un'altra data alla fine del ciclo attività ...

ma, il lavoro non finisce mai ... quindi, non verrebbe mai utilizzato ..;)

5

Proverò a utilizzare qualcosa di soluzione provata e testata. Soluzione Unix Cron Table. Questa soluzione è anche utilizzata da molti altri strumenti come Hudson/Jenkins.

Da wikipedia.

 
* * * * * command to be executed 
┬ ┬ ┬ ┬ ┬ 
│ │ │ │ │ 
│ │ │ │ │ 
│ │ │ │ └───── day of week (0 - 7) (0 or 7 are Sunday, or use names) 
│ │ │ └────────── month (1 - 12) 
│ │ └─────────────── day of month (1 - 31) 
│ └──────────────────── hour (0 - 23) 
└───────────────────────── min (0 - 59) 

Inoltre, consente i nomi di scelta rapida per le voci.

 
Entry  Description                Equivalent To 
@yearly Run once a year at midnight in the morning of January 1    0 0 1 1 * 
@annually 
@monthly Run once a month at midnight in the morning of the first of the month 0 0 1 * * 
@weekly Run once a week at midnight in the morning of Sunday      0 0 * * 0 
@daily  Run once a day at midnight            0 0 * * * 
@hourly Run once an hour at the beginning of the hour      0 * * * * 

Da qui seguente tabella desing.

 
taskID cronExpression preDefinedDefinition 
1  30 * * * *  null 
2  0 * * * *  @hourly 
3  ...   .... 

@Timothy Britt ha detto che questa soluzione non tiene conto di una tantum. Questo è vero. Linux e/o Unix hanno anche un comando chiamato at. Sembra che al punto vendita le sue voci in un file separato e il demone separato monitora questo file. Se vogliamo includere lavori singoli in questa tabella. Potremmo aggiungere una colonna booleana aggiuntiva OneTimeOnly. Oppure un'altra tabella che include solo lavori una volta sola.

+0

Questa soluzione non ha tenuto conto di una tantum. –

+0

Suggerisco di usare una colonna aggiuntiva (booleana) per una tantum. Dopo che funziona, dovrebbe essere cancellato. –

+0

La teoria alla base di questa soluzione è applicabile a più sistemi, è altamente flessibile e quindi mi sembra la risposta corretta. –

1

Suggerirei di utilizzare un formato iCalendar standard di settore (http://www.rfc-editor.org/rfc/rfc5545.txt) invece di provare a creare un progetto relazionale per questo. Potresti vedere alcuni esempi here. Dal momento che i tuoi pattern di ricorrenza sembrano piuttosto semplici, la creazione delle espressioni iCalendar per loro dovrebbe essere un compito abbastanza semplice.

Ecco un utile validatore sintassi: http://severinghaus.org/projects/icv/

+0

OP, confronta http://stackoverflow.com/a/30605875: solo osservando la complessità di http://stackoverflow.com/questions/5183630/calendar-recurring-repeating-events-best-storage-method o simile , sembra che un database di regole sia più facile da mantenere e più efficiente rispetto alla mappatura di tali regole in un layout di database. – isync

0

mi hanno preso le risposte qui riportati e venire con la seguente struttura del database:

Column   Data Type 
id    int 
task_name  nvarchar(50) 
frequency_type nvarchar(10) 
runat_day  int 
runat_month  int 
runat_year  int 

I dati si presenta così:

id task_name  frequency_type runat_day runat_month runat_year 
1 Do this Once once   16   2   2018 
2 Do this Monthly monthly   31   0   0 
3 Do this Yearly yearly   28   2   0 
4 Do this Daily daily   0   0   0 
5 Do this Weekly weekly   6   0   0 

La query per tirare il dato si presenta come questo:

DECLARE @chosen_date datetime = '2018-02-28' 
DECLARE @lastDayOfMonth int = datePart(d,dateadd(s,-1,dateadd(mm, datediff(m,0,getdate())+1,0))) 

select task_name 
from scheduled_tasks 
where (frequency_type = 'once' and runat_day = DATEPART(DAY, @chosen_date) and runat_month = DATEPART(MONTH, @chosen_date) and runat_year = DATEPART(YEAR, @chosen_date)) 
    or frequency_type = 'daily' 
    or (frequency_type = 'weekly' and runat_day = DATEPART(WEEKDAY,@chosen_date)) 
    or (frequency_type = 'monthly' and runat_day = DATEPART(DAY, @chosen_date)) 
    or (frequency_type = 'monthly' and @lastDayOfMonth = DATEPART(DAY, @chosen_date) and runat_day >= @lastDayOfMonth) 
    or (frequency_type = 'yearly' and runat_day = DATEPART(DAY, @chosen_date) and runat_month = DATEPART(MONTH, @chosen_date)) 

Finora, tutti i miei casi d'uso sono giunti correttamente, anche le date di fine mese che cadono in un giorno che non esiste nel mese specificato vengono gestite correttamente (ad es.Il 31 di ogni mese verrà comunque attivato il 28 febbraio)

I campi che non sono richiesti per un determinato tipo di frequenza hanno semplicemente zero o null in essi e vengono ignorati dalla query.

Non tiene in considerazione un evento annuale che si verifica il 29 febbraio in un anno bisestile, né considera l'ora del giorno in alcun modo.

Problemi correlati