Strategia per interrogazione dati storici

di il
4 risposte

Strategia per interrogazione dati storici

Buonasera e buone feste a tutto il forum.

Ho dovuto affrontare in questi giorni la stradiscussa questione dell'esigenza di interrogare tab che contengono dati che variano nel tempo.

Conservo sempre, per abitudine codice che ritengo mi possa servire anche se non nell'immediato ed in questo caso ne ho usato uno di cui non ricordo al momento l'autore, ma vado subito alla questione.

Ho trovato al momento due fattispecie:

1)Prelevo dalla Tb Storico un dato storicizzato ad una data è lo visualizzo in un controllo, lo uso in un recordset  etc nel caso in specie si tratta di    regimi fiscali vigenti ad una data  o scelti da una ditta .

2)E' il classico caso della variazione degli indirizzi nel tempo in questo caso il dato temporale deve essere filtrato in una maschera o un report.

1° caso la TbStorico si sarebbe dovuta presentare  con questi Campi:

Pk IdRegime - Regime - Dal - Al 

la Tb così strutturata presenta due problemi il primo pratico nell'inserimento di un nuovo record bisogna inserire la data fine del record precedente e la data inizio del periodo successivo (sembra una questione di lana caprina ma vi garantisco che ci sono utenti capaci di tutto)

Il secondo problema riguarda soltanto l'economia del codice per stabilire qual' é il record  vigente, per capirci quello che presenta un “AL” nullo

è necessaria un query (perlomeno io ho fatto così) ecco la stringa:

SELECT TbRegimi.IdRegime, TbRegimi.Regime, TbRegimi.Dal, TbRegimi.Al, IIf(IsNull([Al]),Date(),[al]) AS AData
FROM TbRegimi;

  L'esigenza nasce per avere la data odierna nell' “AL” assente.

Per l'Interrogazione ho utilizzato questa Function:

Public Function RegimeFiscaleAL(TuaData As Date) As Integer
   Dim rst As DAO.Recordset
Set rst = DBEngine(0)(0).OpenRecordset("QrRegimi", 2)
   With rst
      .FindFirst "dal<=" & CLng(CDate(TuaData)) & " And AData> " & CLng(CDate(TuaData))
   If Not .NoMatch Then
       RegimeFiscaleAL = .Fields("IdRegime")
   Else
       RegimeFiscaleAL = "0"
   End If
   .Close
End With
Set rst = Nothing
End Function
La chiamata della funzione è questa  =RegimeFiscaleAL([DataTest])

Tutto funziona mah ho deciso che non funziona: l'inserimento delle due date è farraginosa e inutile, la query mi disturbava parecchio ed era foriera di errori:

Ho trasformato tutto cosi la TbStorico si presenta cosi

Pk IdRegime - Regime - Dal

L'inserimento è più immediato (una data) la query non giova più.

L'interrogazione avviene in questo modo è funziona:

Public Function RegimeDAL(TuaData As Date) As Integer
Dim rst As DAO.Recordset
Set rst = DBEngine(0)(0).OpenRecordset("TbRegimi", 2)
With rst
      .FindLast "dal<=" & CLng(CDate(TuaData))
   If Not .NoMatch Then
       RegimeDAL = .Fields("IdRegime")
   Else
       RegimeDAL = "0"
   End If
   .Close
End With
Set rst = Nothing
End Function

Domanda cosa ne pensate, potrei avere qualche problema, c'è un motivo tecnico per cui si inserisce “DAL-AL”?

Saluti e grazie anticipate a chi vorrà rispondere.

4 Risposte

  • Re: Strategia per interrogazione dati storici

    Il problema che stai affrontanto e' tutt'altro che semplice da risolvere.
    Non e' questione di codice, ma di “logica” che i database relazionali normali non supportano in modo “nativo”.
    In teoria esisto i “database temporali” 

    https://www.corsi.univr.it/documenti/OccorrenzaIns/matdid/matdid240602.pdf

    https://en.wikipedia.org/wiki/Temporal_database 

    che permettono di fare delle query ed ottenere esattamente quello che serve.
    Nel caso di un normale DBMS, bisogna integrare query e codice.

    L'approccio e' questo:

    1. hai una serie di “eventi”. Che cosa sia un “evento” lo decidi tu
    2. ogni evento ha una “data di inizio”
    3. l'evento termina quando inserisci lo stesso “evento” con una NUOVA data di inizio. In questo modo, non ti serve indicare la data di fine, perche' e' automaticamente dedotta dal fatto che il nuovo evento ha una nuova data di inizio.

    Ora hai un “istante di tempo” e devi capire QUALE evento considerare. Fai una query in questo modo:

    1. ricerchi TUTTI gli eventi (del tipo che ti interessa) che hanno le date di inizio che PRECEDONO (o sono UGUALI) l'istante di tempo che ti interessa, e li ordini in modo DECRESCENTE sulla data di inizio
    2. l'evento che ti serve e' il PRIMO della lista

    In questo modo puoi pescare l'evento “attivo” in QUALUNQUE istante di tempo.

    Se invece ti serve sapere quali eventi sono attivi in un INTERVALLO di tempo di tua scelta, lo puoi fare con un approccio simile al precedente, con un po' di logica in piu': ad ogni evento assegni un “id” univoco/incrementale che mantiene l'ordine temporale.

    Identificihi il PRIMO evento (ed i PRIMO id), quindi l'ULTIMO evento ( e l'ULTIMO id). 
    A questo punto gli eventi attivi nell'intervallo di interesse sono tutti quelli con gli id compresi tra il primo e l'ultimo (inclusi).

    Un'ulteriore “generalizzazione” e' aggiungere all'evento lo stato “ATTIVO/NON ATTIVO” (VERO/FALSO, 1/0): questo ti permette di modellare il caso in cui l'evento si attiva fino ad una certa data, poi si disattiva fino ad un'altra data, quindi si riattiva/disattiva, e cosi' via.

    La prima soluzione funziona ad esempio per l'IVA: hai l'IVA al 18% fino ad una certa data, nell'istante successivo al 20% fino ad'un'altra data, quindi al 22%, ecc.

    La seconda soluzione funziona per un contratto d'affitto: il contratto parte da una certa data fino alla data di termine, poi per un certo periodo l'appartamento e' “sfitto”, quindi viene riaffittato, ecc…

    Un ulteriore “generalizzazione” e' avere PIU' di 2 stati. Invece che un unico stato (prima soluzione) o 2 (seconda soluzione), K stati che seguono un certo “automa a stati” (cioe' regole ben definite per passare da uno stato all'altro).

  • Re: Strategia per interrogazione dati storici

    07/01/2023 - migliorabile ha scritto:


    …….

    L'approccio e' questo:

    1. hai una serie di “eventi”. Che cosa sia un “evento” lo decidi tu
    2. ogni evento ha una “data di inizio”
    3. l'evento termina quando inserisci lo stesso “evento” con una NUOVA data di inizio

    Ora hai un “istante di tempo” e devi capire QUALE evento considerare. Fai una query in questo modo:

    1. ricerchi TUTTE le date di inizio che PRECEDONO (o sono UGUALI) l'istante di tempo che ti interessa (e per l'event che ti interessa), e le ordini in modo DECRESCENTE sulla data di inizio
    2. l'evento che ti serve e' il PRIMO della lista

    In questo modo puoi pescare l'evento “attivo” in QUALUNQUE istante di tempo.

    Se invece ti serve sapere quali eventi sono attivi in un INTERVALLO di tempo di tua scelta, lo puoi fare con un approccio simile al precedente, con un po' di logica in piu': ad ogni evento assegni un “id” univoco/incrementale che mantiene l'ordine temporale.

    Identificihi il PRIMO evento (ed i PRIMO id), quindi l'ULTIMO evento ( e l'ULTIMO id). 
    A questo punto gli eventi attivi nell'intervallo di interesse sono tutti quelli con gli id compresi tra il primo e l'ultimo (inclusi).

    ……

    Ti ringrazio per la risposta celere, molto dettagliata e per  la documentazione fornita che conto di approfondire in ogni caso.

    Ho potuto notare che concordi con l'uso di una sola data “Dal” , per il resto approfondisco e creerò nuovi post nel caso avessi la necessità.

    Grazie ancora, saluti.

  • Re: Strategia per interrogazione dati storici

    Attento: usare SOLO la data di partenza non e' “obbligatorio”

    Nessuno ti vieta di usare l'intervallo [data_inizio, data_fine], con l'accorgimento di usare, ad esempio, il “31/12/9999” (o anche solo il 31/12/2199 tanto in quella data sarai abbondantemente morto ;-) , con il 31/12/2099 magari sei ancora vivo e ti rompono le scatole per aggiustare il programma ;-) ) come “data di fine” per quegli eventi che sono attivi ORA.

    in questo caso la query dovra' essere: “blablabla WHERE evento.data_inizio <= data_di_interesse < evento.data_fine AND blablabla”.

    Nota: c'e' un pasticcio impasticciato se usi il "minore_o_uguale" SIA per la data di inizio che per la data di fine. SE le due date coincidono E l'istante di tempo di interesse e' ESATTAMENTE lo stesso, quale evento devi considerare? 
    Quello APPENA CONCLUSO OPPURE quello APPENA INIZIATO ?
    Soluzione: scegli una convenzione e la segui

    Usare una data abbondantemente futura ti permette di semplificare la query.
    Poi, ovviamente, se aggiungi l'evento con un nuovo intervallo di validita, devi assicurarti che gli intervalli non si sovvrappongano (quindi devi aggiornare la data futura)

    E' una questione di quale soluzione e' piu “comoda”/semplice da implementare/che semplifica il maggior numero di interrogazioni che ti servono.

  • Re: Strategia per interrogazione dati storici

    07/01/2023 - migliorabile ha scritto:


    Attento: usare SOLO la data di partenza non e' “obbligatorio”

    Nessuno ti vieta di usare l'intervallo [data_inizio, data_fine], con l'accorgimento di usare, ad esempio, il “31/12/9999” (o anche solo il 31/12/2199 tanto in quella data sarai abbondantemente morto ;-) , con il 31/12/2099 magari sei ancora vivo e ti rompono le scatole per aggiustare il programma ;-) ) come “data di fine” per quegli eventi che sono attivi ORA.

    Mah che dici?

    Per parlare cosi, evidentemente non mi conosci e dire che avevo già postato il codice con le 2 date mah, riposto:

    SELECT TbRegimi.IdRegime, TbRegimi.Regime, TbRegimi.Dal, TbRegimi.Al, IIf(IsNull([Al]),Date(),[al]) AS AData
    FROM TbRegimi;

    Scritta cosi la query è categoricamente escluso che io un giorno possa venire a mancare ahahahahahahah

Devi accedere o registrarti per scrivere nel forum
4 risposte