Come fornire una query personalizzata in base a maschera con il VBA
Impariamo come fornire all'utente una query personalizzata in base ai dati di una maschera per effettuare una ricerca con il VBA Visual Basic for Application
Supponiamo che si voglia effettuare una ricerca più complessa nella maschera frmBooks, basata su criteri come il prezzo, il nome dell’autore o iltipo di libro, invece di usare soltanto il titolo del libro.
Si potrebbe spiegare agli utenti come si usano le funzionalitàFiltro in base a maschera per costruire la ricerca, oppure utilizzare il Filtro in base a maschera per costruire facilmente vari criteri OR su test semplici.
Ma se, per esempio, si vogliono trovare tutti i libri che trattino o di Microsoft Access o di Microsoft Excel, non c’è modo di organizzare questa ricerca con le funzionalità standard di filtro.
In realtà, quando si definisce un filtro per una sottomaschera utilizzando il Filtro in base a maschera (come nel caso della sottomaschera Categorie in frmBooks), si filtrano soltanto le righe della sottomaschera: non si troveranno i libri che hanno soltanto una riga corrispondente nella sottomaschera.
Questo esempio nel database Libri esegue una ricerca semplice in base a uno qualunque fra vari criteri di categoria.
Se si vuole cercare una voce che soddisfi tutti i vari criteri, si deve costruire una query complessa che non soltanto cerca una corrispondenza sulle categorie, ma le conta e si accerta che il conteggio sia uguale al numero dei criteri specificati.
Per un esempio di questo tipo di ricerca complessa, si veda la mascherafrmCollegeSearch nel database College.mdb (frmCercaCollege nella versione italiana).
L’unica soluzione, quindi, è quella di predisporre una query in base a maschera personalizzata che fornisca le opzioni per esplorare tutti i campi importanti e costruire poi con uncodice VBA la clausola Where che serve per risolvere il problema dell’esplorazione delle categorie.
Per cominciare, aprire l’applicazione Libri. (Se se ne è usciti passando alla finestra Database, si può riavviare l’applicazione aprendo frmCopyright.)
Registrarsi, fare clic sul pulsante Libri nel pannello comandi principale e quindi fare clic sulpulsante Cerca nella finestra di dialogo Selezione libri.
Dovrebbe comparire la maschera frmBookSearch, riprodotta qui nella figura (figura 1).
Proviamo a selezionare gli autori il cui cognome comincia con la lettera S, i libri con un prezzo compreso fra 15 e 50 dollari e libri su Microsoft Access o Microsoft Excel (dalla casella di riepilogo a discesa Tipi di libri).
Quando si fa clic sui pulsante Cerca, si dovrebbe vedere la maschera frmBooks che si apre, visualizzando tre libri.
Per vedere come avviene questo, è necessario esplorare la struttura della maschera frmBookSearch.
Spostiamoci nella finestra Database e apriamo la maschera in visualizzazione Struttura. Si dovrebbe vedere una finestra come quella della figura (figura 2).
Si osservi che la maschera non è associata ad alcuna origine di record.
I controlli devono essere non associati per accettare qualunque valore che l’utente possa introdurre nei criteri.
Parte del segreto di questa maschera consiste nella casella combinata TypeList e nel suo evento Dopo aggiornamento (AfterUpdate).
Ogni volta che si seleziona una nuova classificazione di tipo nella casella combinata, viene eseguita la seguente routine evento:
Private Sub TypeList_AfterUpdate()
' E' stato selezionato un nuovo codice tipo,
' quindi lo aggiunge alla lista di ricerca
If IsNothing(Me!TypeCodes) Then
Me!TypeCodes = Me!TypeList
Me!Types = Me!TypeList.Column(0)
Else
Me!TypeCodes = Me!TypeCodes & ", " & Me!TypeList
Me!Types = Me!Types & " OR " & Me!TypeList.Column(0)
End If
End Sub
Questo codice crea una clausola IN che contiene i codici dei tipi corrispondenti. Si osservi che questo codice non verifica se è stata selezionata due volte la stessa classificazione; si potrebbe aggiungere questa funzionalità per migliorare il modo di lavorare del codice.
Questo codice immagazzina la stringa IN in un controllo casella di testo nascosto nella maschera e che si chiama TypeCodes. (La sua proprietà Visibile è impostata su No.)
Per vedere come funziona tutto questo, selezionare il controllo TypeCodes, impostare la sua proprietà Visibile su Sì e passare alla visualizzazione Maschera.
Quando si seleziona una nuova classifficazione, si potranno vedere i contenuti di entrambi i controffi che vengono aggiornati.
Un altro approccio potrebbe consistere nel dichiarare una variabile stringa Static all’interno della routine evento per immagazzinarvi la lista dei codici. Se si procede in questo modo, la variabile deve essere di tipo Static, altrimenti verrebbe reimpostata ogni volta che viene chiamata questa routine.
Il grosso del lavoro si svolge quando si fa clic sul pulsante Cerca. Il codice della routine evento per l’evento clic sul pulsante Cerca è presentato qui di seguito.
Private Sub cmdSearch_Click()
Dim db As Database, rst As Recordset
Dim lngCount As Long, intRtn As Integer, strANameComp As String
Dim intI As Integer, strISBN As String 'Parametri di ricerca immessi (almeno speriamo)... 'Cancella la stringa di ricerca globale gstrWhereBook = ""
' e ne analizza una nuova:
If Not IsNothing(Me!ISBNNumber) Then
strISBN = Me!ISBNNumber
'L’ISBN ha una maschera di input per aiutare i ‘utente,
'ma questi potrebbe immettere ogni sorta
'di numeri e trattini. Il codice seguente esegue un’analisi supplementare per ripulirlo!
'Prima, rimpiazza tutti gli spazi in ISBN con punti interrogativi
intI = 1
Do Until intI > Len(strISBN)
If Mid$(strISBN, intI, 1) = " " Then
If intI = 1 Then
strISBN = "?" & Mid$(strISBN, intI + 1)
Else
strISBN = Left$(strISBN, intI - 1) & "?" & Mid$(strISBN, intI + 1)
End If
End If
' Controlla se ci sono trattini nei posti giusti/sbagliati
If intI = 2 Or intI = 8 Or intI = 12 Then
' Se sta nelle posizioni 2, 8, o 12, allora il trattino è OK
If Mid$(strISBN, intI, 1) = "-" Then
Else
'Altrimenti lo toglie di mezzo!
strISBN = Left$(strISBN, intI - 1) & "?" & Mid$(strISBN, intI)
End If
Else
If Mid$(strISBN, intI, 1) = "-" Then
If intI = 1 Then
strISBN = "?" & strISBN
Else
' Verifica che non ci si ano troppi trattini'
If intI > 12 Then
'Rimpiazza il trattino se va oltre la posizione 12
strISBN = Left$(strISBN, intI - 1) & "?" & Mid$(strISBN, intI + 1)
Else
'Scarica il trattino se nella posizione <=12
strISBN = Left$(strISBN, intI - 1) & "?" & Mid$(strISBN, intI)
End If
End If
End If
End If
intI = intI + 1
Loop
Me!ISBNNumber = Left$(strISBN, 13)
'Ora il risultato dovrebbe essere un ISBN pulito nella forma:
'?-?????-???-?
'nel quale l’utente potrebbe aver specificato cifre per uno o più dei punti interrogativi.
gstrWhereBook = "[ISBNNumber] Like " & Chr$(34) & Me!ISBNNumber
'Aggiunge “*“ in coda, per buona misura,..
If Right$(Me!ISBNNumber, 1) = "*" Then
gstrWhereBook = gstrWhereBook & Chr$(34)
Else
gstrWhereBook = gstrWhereBook & "*" & Chr$(34)
End If
End If
'*** Controlla se è stato chiesto un titolo
If Not IsNothing(Me!Title) Then
If IsNothing(gstrWhereBook) Then
gstrWhereBook = "[Title] Like " & Chr$(34) & Me!Title
Else
gstrWhereBook = gstrWhereBook & " AND [Title] Like " & Chr$(34) & Me!Title
End If
If Right$(Me!Title, 1) = "*" Then
gstrWhereBook = gstrWhereBook & Chr$(34)
Else
gstrWhereBook = gstrWhereBook & "*" & Chr$(34)
End If
End If
'*** Vede se c’è un nome o un cognome di autore
If Not IsNothing(Me!LastName) Then
strANameComp = "[LastName] Like " & Chr$(34) & Me!LastName
If Right$(Me!LastName, 1) = "*" Then
strANameComp = strANameComp & Chr$(34)
Else
strANameComp = strANameComp & "*" & Chr$(34)
End If
End If
If Not IsNothing(Me!FirstName) Then
If IsNothing(strANameComp) Then
strANameComp = "[FirstName] Like " & Chr$(34) & Me!FirstName
Else
strANameComp = strANameComp & " AND [FirstName] Like " & Chr$(34) & Me!FirstName
End If
If Right$(Me!FirstName, 1) = "*" Then
strANameComp = strANameComp & Chr$(34)
Else
strANameComp = strANameComp & "*" & Chr$(34)
End If
End If
If Not IsNothing(strANameComp) Then ' Abbiamo costruito un altro confronto?
If IsNothing(gstrWhereBook) Then
gstrWhereBook = "[ISBNNumber] IN (Select ISBNNumber From qryBookAuthors Where " & strANameComp & ")"
Else
gstrWhereBook = gstrWhereBook & " AND [ISBNNumber] IN (Select ISBNNumber From qryBookAuthors Where " & strANameComp & ")"
End If
End If
If Not IsNothing(Me!LowPrice) Then
If IsNothing(gstrWhereBook) Then
gstrWhereBook = "[SuggPrice] >= " & Me!LowPrice
Else
gstrWhereBook = gstrWhereBook & " AND [SuggPrice] >= " & Me!LowPrice
End If
End If
'* * * Imposta il confronto sul prezzo
If Not IsNothing(Me!HighPrice) Then
If IsNothing(gstrWhereBook) Then
gstrWhereBook = "[SuggPrice] <= " & Me!HighPrice
Else
gstrWhereBook = gstrWhereBook & " AND [SuggPrice] <= " & Me!HighPrice
End If
End If
'* * * Imposta la verifica su “contiene disco”
If Me!Disk Then
If IsNothing(gstrWhereBook) Then
gstrWhereBook = "([Disk] Is Not Null)"
Else
gstrWhereBook = gstrWhereBook & " AND ([Disk] Is Not Null)"
End If
End If
'Imposta la verifica su Esaurito
If Me!OutOfPrint Then
If IsNothing(gstrWhereBook) Then
gstrWhereBook = "(Not [OutOfPrint])"
Else
gstrWhereBook = gstrWhereBook & " AND (Not [OutOfPrint])"
End If
End If
' Costruisce la stringa IN per i tipi di codice
If Not IsNothing(Me!TypeCodes) Then
If IsNothing(gstrWhereBook) Then
gstrWhereBook = "[ISBNNumber] IN (Select ISBNNumber From qryBookCategories Where CategoryID IN (" & Me!TypeCodes & "))"
Else
gstrWhereBook = gstrWhereBook & " AND [ISBNNumber] IN (Select ISBNNumber From qryBookCategories Where CategoryID IN (" & Me!TypeCodes & "))"
End If
End If
' Se non ci sono criteri, non è richiesta alcuna attività!
If IsNothing(gstrWhereBook) Then
MsgBox "No criteria specified.", vbExclamation, "Books"
Exit Sub
End If
'*** Cerca in base alla stringa che è stata costruita
' Nasconde questa maschera e attiva la clessidra
Me.Visible = False
DoCmd.Hourglass True
If IsLoaded("frmBooks") Then ' If books form already open,
' allora si limita a filtrarla
Forms!frmBooks.SetFocus
DoCmd.ApplyFilter , gstrWhereBook
If Forms!frmBooks.RecordsetClone.RecordCount = 0 Then
DoCmd.Hourglass False
MsgBox "No Books meet your criteria", vbExclamation, "Books"
DoCmd.ShowAllRecords
If gintIsAdmin Then
Forms!frmBooks!cmdAddNew.Visible = True
Else
Forms!frmBooks!cmdAddNew.Visible = False
End If
Forms!frmBooks!cmdShowAll.Visible = False
Me.Visible = True
Exit Sub
End If
If IsNothing(Me!TypeCodes) And (Not IsNothing(strANameComp)) Then
'Se non sono state indicate categorie dei libri, ma si fa una ricerca sul nome,
'attiva l’opzione per visualizzare l’autore
Forms!frmBooks!tabDisplay = 1
End If
Forms!frmBooks!cmdAddNew.Visible = False
Forms!frmBooks!cmdShowAll.Visible = True
DoCmd.Hourglass False
Else
' Trova se ci sono libri che soddisfano la clausola Where
Set db = CurrentDb
Set rst = db.OpenRecordset("SELECT DISTINCTROW " & _
"tblBooks.ISBNNumber " & _
"FROM tblBooks" & _
" WHERE " & gstrWhereBook & ";")
' Se non ne trova, lo dice e torna
'a rendere visibile il controllo
If rst.RecordCount = 0 Then
DoCmd.Hourglass False
MsgBox "No Books meet your criteria", vbExclamation, "Books"
gstrWhereBook = ""
Me.Visible = True
rst.Close
Exit Sub
End If
' Si porta sull’ultima riga per ottenere un conteggio accurato dei record
rst.MoveLast
lngCount = rst.RecordCount
DoCmd.Hourglass False
'Se sono più di 10, chiede se può bastare vedere un riepilogo
If lngCount > 10 Then
intRtn = MsgBox("More than 10 books meet your criteria. " & _
"Click Yes to see a summary list for all " & lngCount & _
" books found, " & _
"No to see complete data on all that match, " & _
"or Cancel to try again.", vbInformation + vbYesNoCancel, "Books")
Select Case intRtn
Case vbCancel ' Cancel - Try again
Me.Visible = True
Exit Sub
Case vbYes ' Yes - show summary form
DoCmd.OpenForm FormName:="frmBookSummary", WhereCondition:=gstrWhereBook
DoCmd.Close acForm, Me.Name
Forms!frmBookSummary.SetFocus
Exit Sub
End Select
End If
' Risposta No oppure non più di 10, mostra dettagli completi
DoCmd.OpenForm FormName:="frmBooks", WhereCondition:=gstrWhereBook
Forms!frmBooks!cmdAddNew.Visible = False
Forms!frmBooks!cmdShowAll.Visible = True
If IsNothing(Me!TypeCodes) And (Not IsNothing(strANameComp)) Then
' Se non ci sono categorie dei libri, ma si è fatta una ricerca su un nome,
' attiva l’opzione per visualizzare gli autori
Forms!frmBooks!tabDisplay = 1
End If
End If
' Chiude e abbiamo finito
DoCmd.Close acForm, Me.Name
End Sub
La prima parte della routine lavora con i dati immessi nel campo Numero ISBN per verificare che questo abbia un formato corretto.
Sebbene per questo campo esista una maschera di input per aiutare l’utente, la maschera deve essere definita in modo da consentire all’utente di immettere il carattere jolly “?“ ovunque nella stringa.
In questo modo si consente loro di immettere anche trattini in eccesso e altri caratteri. Inoltre, dal momento che la casella di testo non è associata, non esiste una maniera semplice per impedire all’utente di immettere più di 13 caratteri.
(Si potrebbe fissare un limite scrivendo una routine per l’evento TastoGiù, che elimini eventuali digitazioni eseguite dopo la tredicesima posizione.)
Questo codice esamina, un carattere alla volta, quel che è stato immesso.
Se trova un trattino in una posizione scorretta, spinge il testo verso destra e inserisce un carattere jolly punto interrogativo.
Se trova qualcosa che non sia un trattino nelle posizioni 2, 8 e 12, sposta la stringa verso destra e inserisce un trattino.
Infine, preleva iprimi 13 caratteri e vi aggiunge in fondo un carattere jolly asterisco (*), i vari segmenti di codice successivi “assemblano” gradualmente una stringa WHERE esaminando uno per volta i controlli non associati.
Se il campo corrispondente è una stringa, il codice crea un test usando ilpredicato LIKE, in modo che qualunque cosa l’utente immetta possa confrontarsi con qualunque parte del campo nella tabella sottostante, ma non tutti i campi sono stringhe.
Per i due campi del prezzo, il codice costruisce un semplice confronto per “>=“ o “<=“ Se non vi è un disco allegato al libro, il campo [Disk] sarà Null.
Per determinare se un libro è esaurito, basta un semplice test Vero/Falso.
Quando la funzione aggiunge una clausola mentre costruisce la stringa WHERE, inserisce laparola chiave AND fra le clausole se ne esistono già altre.
Siccome l’origine dei record sottostante per lamaschera frmBooks non contiene informazioni dirette sull’autore o sulle categorie, la routine deve costruire unpredicato usando una sottoquery se si chiede una ricerca in base al nome di un autore o a una categoria.
Nel primo caso, la routine esamina entrambi i campi nome e cognome e costruisce due clausole di confronto separate per estrarre ilnumero ISBN.
La sottoquery trova la lista dei numeri ISBN da una query che correla tblBookAuthor (che contiene il campo ISBNNumber) con tblAuthors (nella quale si possono trovare i campi con i nomi degli autori).
Per una ricerca in base alla categorie, la sottoquery usa una query che correla tblBookCategories (che ha ISBNNumber) con tblCategories (che ha il campo CategorylD).
La parte finale della routine costruisce un semplice recordset sulle tabelle usate da entrambe le maschere frmBooks e frmBooksSummary, applicando la clausola WHERE costruita dal codice nella prima metà della routine.
Se non trova alcun record, si serve della funzione MsgBox per informare l’utente, dandogli poi la possibilità di tentare di nuovo.
La prima volta che in un codice di programma si apre un oggetto recordset, la sua proprietà RecordCount è 0 se il recordset è vuoto ed è un valore maggiore di 0 se il recordset contiene qualche record.
Laproprietà RecordCount di un oggetto Recordset contiene soltanto un conteggio del numero delle righe visitate e non il numero delle righe che stanno effettivamente nel recordset.
Per cui, se trova qualche riga, la routine si porta sull’ultima riga del recordset temporaneo per ottenere un conteggio accurato.
Quando il conteggio dei record è superiore a 10, la routine consente all’utente di esaminare in una maschera frmBookSummary un riepilogo dei record trovati, esaminare tutti i dati nella maschera completa frmBooks o di provare un’altra volta.
Qui abbiamo un buon esempio di utilizzo della funzione MsgBox non soltanto per visualizzare qualche dato variabile, ma anche per rispondere a una scelta dell’utente. Ora esamineremo come funziona la maschera frmBookSummary.
Selezionare da un elenco di riepilogo
Come abbiamo visto nella procedura Search_Click, se più di 10 righe corrispondono ai criteri immessi, l’utente può fare una scelta.
Per vedere questa caratteristica all’opera, si chieda nella maschera frmBookSearch di eseguire una ricerca sul valore Advanced come Tipo di libro. (figura 3).
Il risultato dovrebbe presentarsi come nella figura che segue, nella quale si segnala che sono stati trovati21 libri classificati come Advanced.
Quando si fa clic su Sì, la routine Search_Click apre la maschera frmBookSummary, come si vede nella figura (figura 4).
Si può scorrere fino a una riga qualsiasi, mettere il focus su quella riga (accertandosi che l’indicatore di selezione di riga punti a quella riga) e poi fare clic sul pulsante Mostra dettagli per aprire la maschera frmBooks e visualizzare i dettagli per il libro selezionato.
Come si vede, questo è un sistema molto efficiente per aiutare l’utente a restringere una ricerca fino a un libro molto specifico.
Dietro al pulsante Mostra dettagli c’è una semplice routine VBA, illustrata qui sotto, che utffizza il valore corrente del campo ISBNNumber nella maschera per costruire un filtro per il metodo OpenForm.
Private Sub Details_Click()
' Ne è stato scelto uno dalla lista, quindi apre l’elenco dei libri filtrato...
' (Attivato anche se si fa doppio clic in un punto
' qualunque della riga)
gstrWhereBook = "[ISBNNumber] = """ & Me!ISBNNumber & """"
DoCmd.OpenForm FormName:="frmBooks", WhereCondition:=gstrWhereBook
DoCmd.Close acForm, Me.Name
Forms!frmBooks.SetFocus
Forms!frmBooks!cmdAddNew.Visible = False
Forms!frmBooks!cmdShowAll.Visible = True
End Sub
Collegarsi a dati correlati in un’altra maschera
Un altro modo di gestire ulteriori dati correlati è quello di visualizzare i dettagli di quei dati in un’altra maschera.
La sottomaschera fsubAuthorBooks ha un pulsante di comando su ciascuna riga per collegare l’utente ai dettagli completi del libro selezionato in quella riga.
Quando si fa clic su questo pulsante, il codice VBA apre la maschera frmBooks del libro selezionato nella sottomaschera, come si vede nella figura (figura 5).
Questo è un modo semplice per visualizzare tutti i particolari di uno specifico libro mentre si stanno esaminando dati sugli autori.
Si può trovare un analogo pulsante Dettagli nella maschera fsubBookAuthors, che consente di esaminare i dettagli su un autore mentre si lavora sui dati dei libri.
Esempi di accesso ai dati con VBA Microsoft Access
Tutorials su Microsoft Access
Dr.Maurizio Cucchiara
autore del corso:
"Corso Base di Microsoft Access"
disponibile on line su questo sito
MC2 E-Learning S.a r.l.
Formazione per il Web
http://www.mc2.it/html/access.html
Cerca sul web con Google:
