access vba: per eseguire query con VBA in Microsoft Access conviene distinguere tra query di selezione, che restituiscono record, e query di azione, che modificano i dati. Per molte query di azione il metodo CurrentDb.Execute con dbFailOnError è preferibile a DoCmd.OpenQuery, perché evita dipendenza dagli avvisi dell’interfaccia e offre una gestione degli errori più controllabile. Per query parametriche e query di selezione DAO, QueryDef e Recordset sono strumenti fondamentali.
In questa guida vediamo come lanciare query salvate e SQL dinamico, come leggere risultati, passare parametri, usare transazioni, contare record modificati e affrontare i problemi tipici in Access per Microsoft 365, Access 2024 e Runtime.
Indice
- Query di selezione e query di azione
- OpenQuery e CurrentDb.Execute
- QueryDef e parametri
- Recordset DAO
- SQL dinamico
- Transazioni
- RecordsAffected
- Error handling
- Runtime e 32/64 bit
- SQL Server
- FAQ
Prima distinzione: leggere o modificare dati
Una query SELECT restituisce un insieme di record. UPDATE, APPEND/INSERT, DELETE e MAKE-TABLE modificano o creano dati. Il modo in cui le esegui da VBA dovrebbe riflettere questa differenza. Se vuoi leggere risultati in codice, apri un Recordset. Se vuoi eseguire una query di azione, usa Execute e verifica l’esito.
Non eseguire una query distruttiva mentre stai ancora verificando la logica. Prima trasformala in una SELECT equivalente e controlla quali record verrebbero coinvolti. Fai un backup quando il rischio è concreto.
DoCmd.OpenQuery: semplice ma legato all’interfaccia
DoCmd.OpenQuery "qryNome" apre o esegue una query salvata. È comodo per interazioni semplici, ma con query di azione può mostrare avvisi di conferma. Alcuni sviluppatori disattivano gli avvisi con DoCmd.SetWarnings False; questa tecnica è rischiosa se un errore impedisce di riattivarli.
Se devi usare SetWarnings, assicurati di ripristinarli in una sezione di uscita eseguita anche in caso di errore. In molti casi è comunque preferibile DAO Execute.
CurrentDb.Execute per query di azione
Esempio:
Public Sub AggiornaStati()
Dim db As DAO.Database
Set db = CurrentDb
db.Execute "UPDATE Ordini SET Stato='Scaduto' WHERE DataScadenza < Date() AND Stato<>'Pagato';", dbFailOnError
MsgBox db.RecordsAffected & " record aggiornati."
Set db = Nothing
End Sub
dbFailOnError fa sì che DAO generi errore quando l’operazione non riesce. RecordsAffected consente di sapere quanti record sono stati modificati.
Eseguire una query salvata con Execute
Puoi eseguire una QueryDef salvata:
CurrentDb.QueryDefs("qryAggiornaStati").Execute dbFailOnError
Se vuoi leggere RecordsAffected devi mantenere il riferimento alla QueryDef:
Dim qd As DAO.QueryDef
Set qd = CurrentDb.QueryDefs("qryAggiornaStati")
qd.Execute dbFailOnError
Debug.Print qd.RecordsAffected
Query parametriche con QueryDef
Il QueryDef è particolarmente utile per evitare concatenazioni fragili. Supponiamo di avere:
PARAMETERS pDataInizio DateTime, pDataFine DateTime;
SELECT * FROM Ordini WHERE DataOrdine Between [pDataInizio] And [pDataFine];
In VBA:
Dim qd As DAO.QueryDef
Dim rs As DAO.Recordset
Set qd = CurrentDb.QueryDefs("qryOrdiniPeriodo")
qd.Parameters("pDataInizio") = DateSerial(2026, 8, 1)
qd.Parameters("pDataFine") = DateSerial(2026, 8, 31)
Set rs = qd.OpenRecordset(dbOpenSnapshot)
I parametri tipizzati evitano molti problemi di formato data e quoting.
Aprire un Recordset di selezione
Per leggere i risultati:
Dim rs As DAO.Recordset
Set rs = CurrentDb.OpenRecordset("SELECT IDCliente, Nome FROM Clienti ORDER BY Nome;", dbOpenSnapshot)
Do While Not rs.EOF
Debug.Print rs!IDCliente, rs!Nome
rs.MoveNext
Loop
rs.Close
Set rs = Nothing
Usa dbOpenSnapshot se devi soltanto leggere. Un dynaset è appropriato quando devi modificare record attraverso il recordset.
SQL dinamico: quando serve
È utile quando tabelle, campi o parti della logica cambiano in base al contesto. Evita però di concatenare input utente direttamente in SQL. Per valori, preferisci parametri; per nomi di oggetti, valida contro un insieme atteso.
Se concatenare testo è inevitabile, raddoppia gli apostrofi con Replace(valore, "'", "''"). Per le date usa parametri tipizzati ogni volta che puoi.
Debug.Print per SQL dinamico
Prima di eseguire una stringa complessa, stampa Debug.Print sql. Copiala nella visualizzazione SQL di una query e verifica. Questa tecnica trova rapidamente spazi mancanti, virgolette errate e nomi campo sbagliati.
Query di aggiornamento sicure
Un UPDATE senza WHERE può modificare l’intera tabella. Costruisci quindi la query in due fasi: prima una SELECT con lo stesso WHERE, poi l’UPDATE. Se il numero di record previsto è limitato, puoi aggiungere un controllo di conteggio e interrompere se supera una soglia.
Esempio: se ti aspetti al massimo 500 record e la query ne coinvolge 50.000, blocca l’esecuzione e richiedi verifica.
DELETE: precauzioni
Le query DELETE devono avere backup e criteri verificati. Non usare cancellazioni permanenti se il requisito può essere soddisfatto con un campo Stato o una tabella archivio. Nei sistemi aziendali la tracciabilità può essere più importante del risparmio di spazio.
Append e duplicati
Quando esegui INSERT/APPEND, la chiave univoca deve impedire duplicati. Se l’import può essere ripetuto, rendi il processo idempotente usando chiavi business, ID batch o query che inseriscono solo record mancanti.
Transazioni DAO
Se più query devono riuscire tutte insieme, usa una transazione sul Workspace DAO. Concettualmente: BeginTrans, esegui query, CommitTrans; in caso di errore Rollback. Questo evita di lasciare metà aggiornamento completato.
Le transazioni richiedono attenzione: non mantenerle aperte più del necessario e considera i lock in ambiente multiutente.
Query su tabelle collegate
Execute funziona anche su molte tabelle collegate, ma prestazioni e capacità dipendono dalla sorgente. Su SQL Server, una query Access può essere tradotta via ODBC o elaborata parzialmente localmente. Per operazioni pesanti valuta pass-through o stored procedure sul server.
Pass-through query
Una pass-through invia SQL direttamente al server ODBC. È utile per sfruttare T-SQL, stored procedure e processing server-side. Non usa la sintassi Access SQL per il contenuto SQL. Imposta Connect e ReturnsRecords in base all’operazione.
Con dati sensibili evita password hard-coded nella stringa ODBC. Usa autenticazione e configurazioni appropriate.
Query non aggiornabile
Se un recordset basato su una query non è aggiornabile, la causa può essere join, aggregazioni, DISTINCT, union o sorgenti particolari. Non cercare di forzare l’aggiornamento via VBA senza capire il motivo. Modifica la query o esegui un UPDATE mirato sulla tabella corretta.
Gestire parametri di maschera
Una query salvata può riferirsi a Forms!frmFiltro!txtData. Funziona se la maschera è aperta, ma rende la query dipendente dalla UI. Per procedure riutilizzabili e batch, parametri espliciti QueryDef sono più robusti.
Query e Access Runtime
Runtime può eseguire query da VBA. Evita però procedure che richiedono all’utente di aprire query in struttura o correggere parametri manualmente. L’app deve gestire input tramite maschere e messaggi chiari.
32 bit e 64 bit
DAO e il normale SQL Access funzionano in entrambe le architetture Office. I problemi emergono se il progetto usa provider o driver esterni. In SQL Server verifica il driver ODBC installato nella bitness corretta.
Microsoft 365 e Access 2024
Le tecniche DAO e DoCmd descritte sono proprie di Access desktop moderno. Microsoft Learn mantiene il riferimento del modello a oggetti Access e DAO. Prima di usare proprietà specifiche verifica la documentazione corrente.
Gestione errori
Schema:
On Error GoTo GestioneErrore
' esecuzione query
Uscita:
Exit Sub
GestioneErrore:
MsgBox "Errore " & Err.Number & ": " & Err.Description
Resume Uscita
In produzione registra anche il nome query e i parametri, ma non dati sensibili inutili.
Controllare RecordsAffected
Dopo un UPDATE o DELETE verifica il numero di record. Se zero può significare che il filtro non ha trovato corrispondenze; se enorme può indicare un WHERE errato. Trasforma questo numero in una metrica di sicurezza.
Ottimizzare le prestazioni
Evita di eseguire una query per ogni riga quando una singola query set-based può fare il lavoro. Indici sui campi usati nei criteri e join possono migliorare notevolmente le prestazioni. Su tabelle collegate, riduci i dati trasferiti.
Problemi comuni
Troppi parametri previsti
Spesso un nome campo è scritto male o un riferimento Forms non viene risolto.
Tipo dati non corrispondente
Controlla tipi parametri e valori Null. Dichiarare PARAMETERS nella query aiuta.
Query non aggiornabile
Rivedi struttura e sorgenti. Non tutte le SELECT permettono modifiche.
Avvisi disattivati
Se hai usato SetWarnings False, assicurati di riattivarli in uscita.
Prestazioni lente
Controlla indici, funzioni nei criteri, join e quantità di dati trasferiti dalla rete.
Checklist
Classifica la query, prova come SELECT, verifica WHERE, usa dbFailOnError, parametri tipizzati, RecordsAffected, transazioni quando necessarie e log. Testa zero record, molti record, Null, rete non disponibile e permessi insufficienti.
Per query critiche crea casi di test ripetibili e mantieni una copia di backup. In multiutente limita la durata delle transazioni e osserva eventuali lock.
FAQ
OpenQuery o Execute?
OpenQuery è comodo per interfaccia e query visibili; Execute è spesso preferibile per query di azione controllate da codice.
Come leggo i risultati di una SELECT?
Apri un DAO.Recordset, preferibilmente snapshot se devi solo leggere.
Come passo date senza errori?
Usa QueryDef con parametri DateTime.
Come so quanti record sono stati aggiornati?
Leggi RecordsAffected sull’oggetto Database o QueryDef che ha eseguito la query.
Posso usare transazioni?
Sì, DAO Workspace supporta transazioni. Usale per gruppi di modifiche che devono essere atomiche.
Approfondimenti
- Come usare VBA in Access
- Testare una query prima di eseguirla
- Query SQL pass-through in Access
- Tutte le Guide Access
- Microsoft Learn: DAO Execute
Conclusione
Eseguire query con VBA in Access è affidabile quando separi lettura e modifica, usi parametri tipizzati, controlli RecordsAffected e gestisci gli errori. Per query di azione privilegia Execute con dbFailOnError; per letture usa Recordset; per parametri usa QueryDef. Aggiungi transazioni quando più modifiche devono riuscire insieme e considera pass-through per carichi SQL Server. Questo approccio rende le automazioni più prevedibili, sicure e performanti.