Query di aggiornamento

di il
10 risposte

Query di aggiornamento

Buongiorno, avrei bisogno di chiedere un aiuto/consiglio su una query di aggiornamento. Non ho molta esperienza e neanche tanta dimestichezza in VBA. Più che altro mi arrangio con quello che trovo in rete e qualche nozione acquisita in passato. Questo per dire che mi scuso in anticipo se non mi esprimo bene.

Passo ai problemi:

Ho una tabella (tblElencoNominativi) con i classici campi Id; Cognome; Nome; DataDiNascita; ecc...e una Form che li rappresenta/manipola


Oltre questi campi ho altri campi destinati all'inserimento di date (DataRilascioCertificato, DataScadenzaCertificato, DataInvito) che vengono visualizzati in form delle textbox (txtRilascioCertificato; txtInvito; txtScadenzaCertificato)

Il mio primo problema è la dichiarazione di questi campi che io per ora da neofita li ho dichiarati Data/Ora. Quindi una volta che ho spiegato il mio problema, vorrei capire, facendo un passo indietro, se la dichiarazione Data/Ora è corretta oppure bisogna trasformarli in Testo Breve.

Ora il mio obiettivo è quello di creare tre ipotesi su evento click del btnCorferma:

1) Se textbox txtRilascioCertificato è maggiore di txtInvito allora il campo DataInvito si deve cancellare e campo DataScadenzaCertificato deve corrispondere al contenuto della textbox txtRilascioCertificato + 5 anni

2) Se txtRilascioCertificato è vuota deve svuotare i campi DataRilascioCertificato e DataScadenzaCertificato

3) Se txtInvito è vuota deve svuotare il campo DataInvito

Io ho provato a buttar giù due righe ma ovviamente sbaglio. Faccio confusione tra dichiarazioni di variabili, date, stringhe, ecc....
Private Sub btnConferma_Click()
'PULSANTE CONFERMA
Dim sDataScadenza As String, sDataRilascioCertificato As String, sDataInvito As String

Refresh
    
    sDataRilascioCertificato = CDate(txtRilascioCertificato)
    sDataInvito = CDate(txtInvito)
    
    Select Case sDataRilascioCertificato
    
    Case Is > sDataInvito
        DoCmd.SetWarnings False
        CurrentDb.Execute "UPDATE tblElencoNominativi SET [Data invito] = Null WHERE [IdNominativo] = " & OpenArgs
        DoCmd.SetWarnings True
    
    Case Is <> ""
        sDataScadenza = DateAdd("yyyy", 5, CDate(sDataRilascioCertificato))
        DoCmd.SetWarnings False
        CurrentDb.Execute "UPDATE tblElencoNominativi SET [Data scadenza certificato] = " & sDataScadenza & " WHERE [IdNominativo] = " & OpenArgs
        DoCmd.SetWarnings True
    
    Case Is = ""
        DoCmd.SetWarnings False
        CurrentDb.Execute "UPDATE tblElencoNominativi SET [Data scadenza certificato] = Null, [Data rilascio certificato] = Null WHERE [IdNominativo] = " & OpenArgs
        DoCmd.SetWarnings True
    
    End Select
    
    DoCmd.Close acForm, Me.Name
    
    Forms("frmElencoNominativi").Requery
        
End Sub
Ho letto che la funzione DateAdd restituisce un valere Variant e quindi immagino che così scritto già parto col piede sbagliato....
In altre parole:

in una maschera inserisco una data di rilascio certificato medico. A questa data bisogna aggiungere 5 anni e visualizzare questa nuova data in una textbox corrispondente al campo DataScadenzaCertificato. Un mese prima che scade il certificato mando un invito alla persona interessata il quale dovrà attivarsi per presentare un nuovo certificato. Questa data di invito la devo annotare nel database. Questa persona dopo qualche settimana mi porterà il nuovo certificato, io inserirò nel database la nuova scadenza. A questo punto se la nuova scadenza risulterà maggiore della data d'invito allora la data di invito non servirà più, quindi si deve eliminare.
Ma in tutti i casi queste date posso anche ometterle, quindi i campi possono risultare vuoti. La mia routine va in blocco proprio perché le variabili risultano nulle o vuote e ciò che ho scritto non va bene.

10 Risposte

  • Re: Query di aggiornamento

    alexps81 ha scritto:


    Ho una tabella (tblElencoNominativi) con i classici campi Id; Cognome; Nome; DataDiNascita; ecc...
    Ti consiglio di chiamare il campo ID più esplicitamente IDNominativo.

    alexps81 ha scritto:


    Oltre questi campi ho altri campi destinati all'inserimento di date (DataRilascioCertificato, DataScadenzaCertificato, DataInvito) che vengono visualizzati in form delle textbox (txtRilascioCertificato; txtInvito; txtScadenzaCertificato)

    Il mio primo problema è la dichiarazione di questi campi che io per ora da neofita li ho dichiarati Data/Ora. Quindi una volta che ho spiegato il mio problema, vorrei capire, facendo un passo indietro, se la dichiarazione Data/Ora è corretta oppure bisogna trasformarli in Testo Breve.
    Va bene Data/Ora.

    Quello che non va bene è che quei tre campi Data non hanno nulla a che vedere con la tabella tblElencoNominativi. Prevedi una tabella...che nominerei Eventi con i campi:
    IDEvento (PK, numerazione automatica)
    DataEvento (Data/Ora)
    TipoEvento (Testo, qui ci scrivi se si tratta di RilascioCertificato, ScadenzaCertificato, Invito...puoi avere anche altre voci...)
    IDNominativo (FK, Numerico)

    A seguire crei la relazione Nominativi.IDNominativo uno-a-molti Eventi.IDNominativo
  • Re: Query di aggiornamento

    Ciao e grazie....

    Si cmq il campo Id già lo avevo chiamato IdNominativo

    Per quanto riguarda la tabella...effettivamente sarebbe più ordinato/corretto creare una relazione tra tabelle ma sto lavorando su dei dati già esistenti (circa 4000 record). Dovrei creare una nuova tabella e riportare con molta attenzione tutti i dati corrispondenti...se eventualmente non è una cosa così importante creare la relazione preferirei continuare il lavoro così com'è in un unica tabella. Ma ad ogni modo, diciamo che io riuscissi a creare questa relazione e a riportare i dati esistenti in modo corretto...come dovrei proseguire in ambito di programmazione VBA? Perché da quello che ho letto la gestione dei campi DATA non è così semplice. Per ora ho difficoltà quando questi campi sono vuoti o nulli. Cioè se lancio le query così come le ho scritte e tenendo i campi vuoti mi genera l'errore relativo alla stringa nulla.
  • Re: Query di aggiornamento

    Partiamo dal fatto che sia giusto avere 2 tabelle. Poi, per aggiustare il tutto:
    1. Fai una copia del tuo database...non si sa mai combini pasticci.
    Con un po' di pazienza:
    2. Crea una query dalla tabella Nominativi con i soli campi IDNominativo, DataRilascioCertificato
    3. Aggiungi a questa query un campo e ci scrivi:
    TipoEvento: "RilascioCertificato"
    4. Modifica la query in "query di accodamento" e gli dici che vuoi accodare alla tabella Eventi (che avrai predisposto come dicevo prima).
    5. Esegui una sola volta la query di accodamento.
    6. Modifica la query avente i campi IDNominativo, DataScadenzaCertificato e
    TipoEvento: "ScadenzaCertificato"
    7. Esegui una sola volta la query di accodamento.
    8. Modifica la query avente i campi IDNominativo, DataInvito e
    TipoEvento: "Invito"
    9. Esegui una sola volta la query di accodamento.
    10. Adesso apri la tabella Eventi e controlla che tutti i valori siano coerenti. Se sì, puoi eliminare la query di accodamento.
  • Re: Query di aggiornamento

    Ok. Domani con calma leggo tutto e cerco di seguire passo passo i tuoi suggerimenti. Ma mi sfugge una cosa...ma tutto questo che mu hai appena detto sbaglio o non risolve il discorso di aggiornare i campi se sono vuoti, oppure aumentare il campo Scadenza Certificato di + 5 anni rispetto alla data del rilascio o piuttosto cancella il campo Data Invito in base al confronto con campo Rilascio Certificato...così come spiegavo all'inizio del 3D...oppure non sto capendo? Magari questo che mi vuoi far fare è il primo passaggio?
  • Re: Query di aggiornamento

    alexps81 ha scritto:


    mi sfugge una cosa...ma tutto questo che mu hai appena detto sbaglio o non risolve il discorso di aggiornare i campi se sono vuoti, oppure aumentare il campo Scadenza Certificato di + 5 anni rispetto alla data del rilascio o piuttosto cancella il campo Data Invito in base al confronto con campo Rilascio Certificato...così come spiegavo all'inizio del 3D...
    Sinceramente, dopo averti dato il suggerimento di normalizzare su 2 tabelle...ho ignorato tutto il ragionamento logico che avresti impiantato tu al riguardo (+ 5 anni ecc...). Se non altro non so esattamente "di cosa parla il tuo database". Potresti raccontare qualche esempio concreto per farmi capire meglio?
  • Re: Query di aggiornamento

    Ok ok...
    Partiamo col fatto che sto cercando di realizzare un db per un collega di lavoro. In passato questo collega ha realizzato (secondo le sue conoscenze) un archivio di dati in access.

    C'è un elenco di Cognomi, Nomi, Date di nascita, indirizzo di residenza, e così via. Poi sempre in tabella ha aggiunto dei campi DATA che servono ad archiviare la Data del rilascio del certificato medico, la data di scadenza del certificato (+ 5 rispetto alla data di rilascio) e una data di Invito a rinnovare tale certificato.

    Quindi...ipotizziamo che...arriva un utente e deposita il suo certificato medico (per esempio rilasciato il 23/09/2021). Nel campo DataRilascio comparirà 23/09/2021, mentre nel campo DataScadenzaCertificato in automatico ci sarà 23/09/2026 cioè 5 anni in più (5 sono gli anni di validità del certificato).

    In una casella di riepilogo mi compaio tramite una query la lista delle persone che hanno o il certificato scaduto o che sta per scadere.

    Una volta preso nota degli utenti con certificati non in regola, viene appuntato (nel campo DataInvito) la data in cui viene invitato l'utente a presentare il nuovo certificato. Questa DataInvito è pari a 30 gg prima della data di scadenza.
    Quindi manualmente vado ad agire nel campo DataInvito e vado ad inserire (in base all'esempio che sto riportando) 23/08/2026 ( questo però lo farò un mese prima ma nel 2026).

    Dopo pochi giorni l'utente presenta un nuovo certificato con la data del nuovo rilascio...ipotizziamo 30/09/2026...dato che questa data è superiore alla DataInvito (23/08/2026) allora la DataInvito non serve più perciò si può cancellare. Nel frattempo il campo DataScadenzaCertificato dovrà avere come data 30/09/2031...con la speranza che ci arriviamo.

    Può essere però che non è detto che ci siano date in tutti questi campi. Infatti se lancio le query che ho scritto io, nel caso di campi vuoti mi da in errore perché le stringe sono nulle.

    Spero di essermi spiegato bene. So che dirai che il ragionamento è contorto ma alla fine devo cercare di rendere in sottoforma di Maschere ciò che ha fatto lui in passato perché cambiare del tutto sistema non è facile per lui ora che è abituato così da tempo
  • Re: Query di aggiornamento

    Io ho letto e cercato di capire la logica... ma non ci sono riuscito.
    Dal momento che operi da un a Maschera e quando operi sulla registrazione Utente sei su quell'ID ma anche quando fai le segnalazioni sei su quell'ID ed anche quando rinnovi il Certificato sei su quell'ID... mi chiedo perchè devi fare una Query Action.
    Se la maschera contiene i dati da Query con JOIN hai nella form operativa tutti i dati, e su AfterUpdate o su Click di Caricamento de nuovo Certificato vai a modificare nello stesso Record i dati che ti servono.

    La logica poi di diffondere codice incrociato tra le Form è sbagliata, la Form che apri andrebbe aperta in modalità acDialog se proprio ed alla chiusura metti il Requery della Form principale, la stessa che chiama la secondaria, non si mettono codici che fanno richiami di richiami...

    Non tralascio questi aspetti:
    1) Il Refresh non serve
    2) Il SetWarning non serve, se usi Execute
    3) La formattazione delle date è completamente errata per l'uso in una Query o Criterio SQL per Jet.
    4) Dichiari le variabili come Stringa ma poi le vorresti trattare come Date...

    Insomma a mio avviso ci sono molti aspetti funzionali non chiari che rendono il tutto poco comprensibile, condito da errori concettuali discretamente importanti, e si fa fatica a capire se la strada che hai preso sia tecnicamente giusta o no.

    Boh...
  • Re: Query di aggiornamento

    Osserva:
    DataRilascio è un valore che solo l'utente può inserire.
    DataScadenza = DataRilascio + 5 anni. Questo lo può calcolare una funzione di Access (DateAdd)
    DataInvio = DataScadenza - 30 giorni. Anche questo lo può calcolare Access.

    Io non cancellerei i Certificati precedenti, ma terrei uno storico degli stessi. La tabella Nominativi resta con i tipici campi nominativi. Elimina/resetta la tabella Eventi (non avevo capito tutto il meccanismo). La tabella figlia la chiami Certificati con i seguenti campi:
    IDCertificato (PK, numerazione automatica)
    DataRilascio (Data/Ora con un formato di sola Data, per es. "Data in cifre")
    Descrizione (Testo, ce lo sto aggiungendo io...non so...un minimo di descrizione non è prevista?)
    IDNominativo (FK, numerico)

    Ovvia relazione Nominativi.IDNominativo uno-a-molti Certificati.IDCertificati

    1. Costruisci (direi) maschera/sottomaschera Nominativi/Certificati (consiglio la creazione guidata).
    2. In sottomaschera Certificati aggiungi (in visualizzazione struttura maschera) 2 caselle di testo che chiamerai DataScadenza e DataInvio.
    3. Dentro DataScadenza ci scrivi:
    =DateAdd("aaaa";5;[DataRilascio])
    4. Dentro DataInvio ci scrivi:
    =[DataScadenza]-30
    5. Salva tutto

    Il fatto che DataInvio talvolta non serve...va bene lo stesso...vuol dire che non la utilizzerai...ma non succede nulla se appare lo stesso valorizzata: tu la ignori.
  • Re: Query di aggiornamento

    Ciao Osvaldo, ho seguito il tuo consiglio e ti ringrazio perché così come mi hai indicato il database risulta molto più lineare e semplice da gestire. Creare uno storico dei certificati effettivamente può essere importante.

    Ora però, a causa di questa modifica alla struttura del database, ho un nuovo problema da risolvere. Riguarda sempre un discorso legato alle query (quindi se non ci sono problemi io continuerei con questo 3D).

    Passo ad esporlo:

    Nella maschera principale frmElencoNominativi ho 2 ListBox, la prima va ad elencare i nominativi che alla data odierna hanno superato di oltre 30 gg la DataInvito, la seconda ListBox invece va ad elencare quei nominativi che hanno il certificato medico scaduto o in scadenza (30 gg prima).

    Per la prima ListBox (che chiamo ElencoInvito) ho messo come origine riga una query dove al campo DataInvito ho messo come criterio <Date()-30, stessa cosa alla seconda ListBox (che chiamo ElencoDataScadenza) ho messo come origine riga una query dove al campo DataScadenzaCertificato ho messo come criterio <Date()-30.

    Diciamo che funziona...ma non come vorrei, perché adesso, così com'è costruito il db con la relazione una-a-molti, può essere che mi ritrovo più certificati per lo stresso Nominativo mentre prima ne avevo sempre uno solo. Quindi bisognerebbe effettuare un ulteriore filtraggio dei dati. Cioè se ad esempio un Nominativo (che ha come IdNominativo = 1 per esempio) ha 3 date nel campo DataInvito registrate nella tabella certificati (es.: 10/10/2010; 20/08/2015; 01/07/2021) vorrei che la query mi mostri solo il record con la data più recente (perché si presuppone che le altre dato ormai sono superate, la persona ha avuto quegli inviti per regolarizzare certificati scaduti anni prima).

    Riporto un esempio pratico:

    IdNom IdCert Cognome Nome Data invito
    1 1 Paolino Paperino 10/10/2010
    1 2 Paolino Paperino 20/08/2015
    1 3 Paolino Paperino 01/07/2021

    2 1 Pippo Pluto 15/05/2020
    3 1 Kent Clarke 05/02/2015
    3 2 Kent Clarke 07/03/2021


    Come si evince dall'esempio Paolino Paperino e Kent Clarke hanno più di una DataInvito ma a me interessa che la query mi mostri solo quella con data più recente. Quindi devo vedere sono un Paolino Paperino e un solo Clake Kent ma con le date più recenti.

    Come posso risolvere questo problema? Sicuro è una stupidaggine ma mi sono arenato.

    Grazie mille.
  • Re: Query di aggiornamento

    In visualizzazione struttura query, clicca in alto sul tasto Totali. Nella griglia sottostante apparirà un nuovo rigo Formula. In corrispondenza di DataInvito cambia da Raggruppamento a Max.

    P.S.: la discussione ha preso un'altra piega. Sarebbe stato meglio aprire una nuova discussione. Quando in una DiscussioneB e ci sono forti riferimenti a una precedente DiscussioneA, puoi indicare il link corrispondente se serve a far capire meglio di cosa si sta parlando.
Devi accedere o registrarti per scrivere nel forum
10 risposte