Il concetto di impiegare, in una query, le possibili condizioni con cui esaminare i vari intervalli (assegnando Vero o Falso) serve semplicemente per procedere gradualmente (quasi a livello didattico) in modo da poter osservare le modalità con cui il processo avviene (poteva anche essere impiegato un algoritmo compattato o del codice VBA per le funzioni relative).
Viste le difficoltà cerco di fornirti delle indicazioni, nel merito, più esplicative.
Immaginiamo (in una ipotesi di tabella semplificata delle assenze) di avere i seguenti dati di partenza:
ID Dal Al
1 01/01/2015 31/12/2015
2 01/01/2016 02/02/2016
3 03/03/2016 04/04/2016
4 01/06/2016 10/07/2016
5 01/06/2016 11/11/2016
6 01/10/2016 12/12/2016
7 10/10/2016 12/12/2016
8 12/12/2016 31/12/2016
e si voglia ricercare i giorni di assenza che ricadono nel periodo con intervallo:
Partenza Termine
01/07/2016 10/10/2016
Per prima cosa si realizza la query con i campi ([Dal] , [Al]) e si imposta (per semplicità) i valori di ricerca (Partenza, Termine) in modo fisso (dopo si provvederà ad implementare con parametri o attraverso una maschera di selezione delle date).
Il codice SQL sarà qualcosa del genere:
SELECT TabellaPeriodi.Dal, TabellaPeriodi.Al, #7/1/2016# AS Partenza, #10/10/2016# AS Termine
FROM TabellaPeriodi;
Implementerai questa query inserendo il controllo sui vari intervalli (ove siano sovrapponibili le date di ricerca all'interno del periodo di assenza).
Partenza_Interno: IIf([Partenza]>=[Dal] And [Partenza]<=[Al];Vero;Falso)
Termine_Interno: IIf([Termine]>=[Dal] And [Termine]<=[Al];Vero;Falso)
PartenzaTermine_Esterni: IIf([Partenza]<[Dal] And [Termine]>[Al];Vero;Falso)
Il codice SQL risultante sarà qualcosa del genere:
SELECT TabellaPeriodi.Dal, TabellaPeriodi.Al, #7/1/2016# AS Partenza, #10/10/2016# AS Termine,
IIf([Partenza]>=[Dal] And [Partenza]<=[Al],True,False) AS Partenza_Interno,
IIf([Termine]>=[Dal] And [Termine]<=[Al],True,False) AS Termine_Interno,
IIf([Partenza]<[Dal] And [Termine]>[Al],True,False) AS PartenzaTermine_Esterni
FROM TabellaPeriodi;
Attraverso i campi logici calcolati (Partenza_Interno, Termine_Interno, PartenzaTermine_Esterni) si potrà determinare (in base alle loro combinazioni) i vari tipi di intervallo e procedere al relativo calcolo.
Giusto per rendere più chiaro l'esempio, si possono calcolare (in ogni caso) i giorni dei possibili intervalli nel caso in cui:
- sia sovrapponibile in tutto (intervallo di ricerca all'interno del periodo di assenza) si assegna quindi intero periodo (ad esempio nel campo calcolato: GG_tutto_periodo);
- sia sovrapponibile parzialmente, con la data di partenza della ricerca all'interno del periodo di assenze, si assegnano i giorni trascorsi fra la data di partenza della ricerca [Partenza] e quella di fine delle assenze [Al] (ad esempio nel campo calcolato: GG_parte_iniziale);
- sia sovrapponibile parzialmente, con la data di termine della ricerca all'interno del periodo di assenze, si assegnano i giorni trascorsi fra la data di inizio assenze [Dal] e quella del termine della ricerca [Termine] (ad esempio nel campo calcolato: GG_parte_finale);
- non sia sovrapponibile in tal caso o la ricerca comprende il periodo (Dal-Al) oppure il valore dei giorni è pari a zero e quindi è inutile il relativo calcolo.
Per implementare i calcoli dei relativi giorni negli intervalli si può porre:
GG_tutto_periodo: DateDiff("g";[Dal];[Al])+1
GG_parte_iniziale: DateDiff("g";[Partenza];[Al])+1
GG_parte_finale: DateDiff("g";[Dal];[Termine])+1
Il codice SQL implementato sarà qualcosa del genere:
SELECT TabellaPeriodi.Dal, TabellaPeriodi.Al, #7/1/2016# AS Partenza, #10/10/2016# AS Termine,
IIf([Partenza]>=[Dal] And [Partenza]<=[Al],True,False) AS Partenza_Interno,
IIf([Termine]>=[Dal] And [Termine]<=[Al],True,False) AS Termine_Interno,
IIf([Partenza]<[Dal] And [Termine]>[Al],True,False) AS PartenzaTermine_Esterni,
DateDiff("d",[Dal],[Al])+1 AS GG_tutto_periodo,
DateDiff("d",[Partenza],[Al])+1 AS GG_parte_iniziale,
DateDiff("d",[Dal],[Termine])+1 AS GG_parte_finale
FROM TabellaPeriodi;
Infine per ottenere il calcolo dei giorni di assenza relativi all'intervallo impostato, si procede partendo dai due valori logici individuati [Partenza_Interno] e [Termine_Interno] ed in base a questa coppia di valori si determina quale delle condizioni (fra Vero e Falso) sia applicabile, in modo da assegnare i giorni relativi calcolati (GG_tutto_periodo, GG_parte_iniziale, GG_parte_finale) oppure zero.
Dal punto di vista pratico si può impiegare una IIF nidificata (in modo da gestire le quattro condizioni) e determinare un campo calcolato [GGTot] che stabilisca i relativi giorni di assenza, come nel seguente esempio:
GGTot:
IIf([Partenza_Interno]=Vero And [Termine_Interno]=Vero;[GG_tutto_periodo];
IIf([Partenza_Interno]=Vero And [Termine_Interno]=Falso;[GG_parte_iniziale];
IIf([Partenza_Interno]=Falso And [Termine_Interno]=Vero;[GG_parte_finale];
IIf([PartenzaTermine_Esterni]=Vero;DateDiff("g";[Dal];[Al])+1;0))))
Per cui il codice SQL finale, della query, risulta:
SELECT TabellaPeriodi.Dal, TabellaPeriodi.Al, #7/1/2016# AS Partenza, #10/10/2016# AS Termine,
IIf([Partenza]>=[Dal] And [Partenza]<=[Al],True,False) AS Partenza_Interno,
IIf([Termine]>=[Dal] And [Termine]<=[Al],True,False) AS Termine_Interno,
IIf([Partenza]<[Dal] And [Termine]>[Al],True,False) AS PartenzaTermine_Esterni,
DateDiff("d",[Partenza],[Termine])+1 AS GG_tutto_periodo,
DateDiff("d",[Partenza],[Al])+1 AS GG_parte_iniziale,
DateDiff("d",[Dal],[Termine])+1 AS GG_parte_finale,
IIf([Partenza_Interno]=True And [Termine_Interno]=True,[GG_tutto_periodo],
IIf([Partenza_Interno]=True And [Termine_Interno]=False,[GG_parte_iniziale],
IIf([Partenza_Interno]=False And [Termine_Interno]=True,[GG_parte_finale],
IIf([PartenzaTermine_Esterni]=True,DateDiff("d",[Dal],[Al])+1, 0 )))) AS GGTot
FROM TabellaPeriodi;
In modo da ottenere il seguente risultato conclusivo:
Dal Al Partenza Termine Partenza_Interno Termine_Interno GG_tutto_periodo GG_parte_iniziale GG_parte_finale GGTot
01/01/2015 31/12/2015 01/07/2016 10/10/2016 Falso Falso 102 -182 649 0
01/01/2016 02/02/2016 01/07/2016 10/10/2016 Falso Falso 102 -149 284 0
03/03/2016 04/04/2016 01/07/2016 10/10/2016 Falso Falso 102 -87 222 0
01/06/2016 10/07/2016 01/07/2016 10/10/2016 Vero Falso 102 10 132 10
01/06/2016 11/11/2016 01/07/2016 10/10/2016 Vero Vero 102 134 132 102
01/10/2016 12/12/2016 01/07/2016 10/10/2016 Falso Vero 102 165 10 10
10/10/2016 12/12/2016 01/07/2016 10/10/2016 Falso Vero 102 165 1 1
12/12/2016 31/12/2016 01/07/2016 10/10/2016 Falso Falso 102 184 -62 0