Uso del Filtro personalizzato in vba, con le date.   -   Aggiornamento Articolo 21/02/06

Ancora un esercizio basato sull'applicazione del filtro personalizzato, basato sulla ricerca di dati compresi tra una data ed un altra, il tutto realizzato in vba.

Supponiamo di voler filtrare tutti i record  compresi tra  due date, il 10/01/03 e il 15/02/03. Applicheremo quindi il filtro sul campo "data", selezioneremo "personalizzate" nel menù del campo, e si aprirà la finestra per la selezione dei "criteri di ricerca". Ovviamente sceglieremo il primo criterio "uguale o maggiore" del 10/01/03, e come secondo criterio "minore o uguale" a  15/02/03. Se ci aiutiamo usando il "Registratore di macro", vedremo che nelle istruzioni compilate da Excel, alle voci "Criteria1" e "Criteria2", viene usata la seguente sintassi:

omissis...AutoFilter Field:=10, Criteria1:=">=10/01/2003", Operator:= _
xlAnd, Criteria2:="<=15/02/2003"

cioè per l'assegnazione del criterio le date vengono scritte tra doppi apici, con i segni di maggiore (>), o minore (<) e uguale (=).  Con queste istruzioni però il filtro è "statico", se non si creano le routine per poter rendere i "criteri" variabili a piacere. Useremo quindi delle InputBox per l'introduzione delle date, che assegneremo a delle variabili da richiamare come "argomento" dei "Criteria". E qui casca l'asino, almeno per me. Non sono riuscito a trovare la giusta sintassi perchè i "Criteria" riconoscano le stringa di concatenazione che lega i simboli maggiore-minore e la variabile data ottenuta dalle inputbox. Anzi, dirò di più, mentre sul foglio di lavoro, l'applicazione del filtro personalizzato attraverso la procedura attraverso i menù, fornisce i risultati voluti, se si cerca di replicare il filtro, pari pari come lo ha scritto Excel,  usando il codice stesso scritto da Excel, il filtro non funziona. Non capisco perchè, ma a me succede così.

Avrei una soluzione da proporre, in attesa  (trovata: vedi Aggiornamento articolo)  che qualcuno riesca a spiegarmi cose che non so, soluzione che serve ad aggirare l'ostacolo, e funziona egregiamente. Riprendiamo la tabella esempio già usata in altri esempi:

Volendo applicare il filtro sulle date, e visto le motivazioni sopra descritte, ho seguito questa procedura:

  • ho destinato due celle, formattate a "data" del tipo "13/01/02", in cui inserisco i dati che reperisco con due InputBox, e che corrisponderanno alla data di inizio del range di ricerca, e alla data finale.

  • In una colonna a lato della tabella, iniziando dalla stessa riga in cui inizia la tabella, ho inserito una formula condizionale che controlla se la data nella colonna "data", stessa riga, sarà uguale o maggiore rispetto alla data che avremo ottenuto con la prima InputBox, e che sarà stata immessa nella prima delle due celle per questo predisposte, e controlla anche se la data ottenuta con la seconda InputBox e inserita nella seconda cella sarà minore o uguale alla data nella colonna "data" stessa riga. Nel caso di una corrispondenza, nella cella della formula verrà riportato il valore 1, in caso contrario il valore zero.

  • A questa colonna dove ho inserito le formule, applicheremo il filtro. A questo punto avremo bisogno di citare come valore da assegnare a Criteria1, il valore 1, e il gioco è fatto, il filtro in questo modo funziona egregiamente, nascondendo tutte le righe che non corrispondono a 1. Vediamo la tabella:

Le celle evidenziare in giallo, sono le celle che "ospitano" le date introdotte con le InputBox, e potranno essere utilizzate celle "fuori vista", in altra zona del foglio, come pure le formule che ho inserito nella colonna H solo per mostrarle. A partire dalla cella H4, c'è la formula : =SE(E(F4>=$G$1;F4<=$H$1);1;0) che andrà inserita col "trascinamento" anche nelle celle sottostanti, per quanto sarà lunga la tabella. E questo sarà l'effetto del filtro una volta applicato:

Ed ora vediamo le procedure per le InputBox e per l'applicazione del filtro. Premetto che queste routine sono specifiche per la ricerca sulle date di questa tabella. Se si volesse gestire la libertà di scegliere su quale colonna applicare il filtro, dovremo modificarle.

Sub Filtradata()
'dichiarazione delle variabili che conterranno le date introdotte nelle due InputBox
Dim Crituno
Dim Critdue
'assegnazione a Crituno della prima data
Crituno = InputBox("Inserire la prima data")

'se non scriviamo niente si uscirà dalla routine
If Crituno = "" Then Exit Sub

'rendiamo la cella G1 uguale a Crituno, con assegnazione del tipo di dati (CDate) e 'formattazione della data
Range("G1").Value = CDate(Format(Crituno, "dd/mm/yy"))
'si ripete per la seconda InputBox con inserimento della seconda data (Critdue) nell'altra 'cella H1
Critdue = InputBox("Inserire la seconda data")
If Critdue = "" Then Exit Sub
Range("H1").Value = CDate(Format(Critdue, "dd/mm/yy"))
'ora selezioniamo la cella H3 (colonna con le formule) e applichiamo il filtro
Range("H3").Select
Selection.AutoFilter
Selection.AutoFilter Field:=1, Criteria1:=1
'poi selezioniamo la cella A1 per deselezionare la cella del filtro
ActiveSheet.Cells(1, 1).Select
End Sub

 

Aggiornamento Articolo:

Bene, finalmente qualcuno, tal "pellegrino" Cannazza Massimo, riprendendo l'argomento Filtrare Date col vba, ha svelato l'arcano: è solo una questione di "formato data".

La stringa da assegnare ai Criteria deve contenere date in stile inglese, cioè mese/giorno/anno e non come da noi giorno/mese/anno, quindi, visto che l'utilizzo di una "funzione di conversione del tipo" come CDate impegna excel alla conversione di una data già nel formato stile italiano (nel nostro caso), useremo solo la funzione Format(oggetto, "tipo di formato"), ed il filtro lavorerà perfettamente; potremo usare una variabile per comporre la nostra stringa da assegnare ad un Criteria, così:

  • primadata = ">=" & Format(Crituno, "mm/dd/yy")   'concateniamo i simboli di Maggiore o Uguale alla data letta con Crituno e formattata a      mese/giorno/anno e assegniamo la stringa alla variabile "primadata", variabile da usare come argomento di un Criteria, così:

  • Selection.AutoFilter Field:=6, Criteria1:=primadata

oppure, usare direttamente la stringa passandola al Criteria, così:

  • Selection.AutoFilter Field:=6, Criteria1:=">=" & Format(Crituno, "mm/dd/yy"),

Vediamo quindi una routine completa "rifatta" seguendo i concetti appena sopra esposti, e basata sullo schema della tabella vista sopra, dove la colonna delle date è la colonna F, (la n. 6) e le intestazioni di colonna sono sulla riga 3

Sub Filtradata2()
If Worksheets("Foglio1").FilterMode = True Then  
'controlliamo che non sia già inserito il filtro, altrimenti
Worksheets("Foglio1").ShowAllData     
 'lo togliamo
End If
Dim Crituno
Dim Critdue
Crituno = InputBox("Inserire la prima data")
If Crituno = "" Then Exit Sub 
 'se non scriviamo niente nella inputbox, si esce dalla sub
Critdue = InputBox("Inserire la seconda data")
If Critdue = "" Then Exit Sub  
 'se non scriviamo niente nella inputbox, si esce dalla sub
Range("A3").Select     
'selezioniamo la cella di  inizio intestazioni di riga (campi tabella)
'e applichiamo il filtro, scegliendo il campo 6 (colonnaF) come campo da filtrare, usando i Criteria come spiegato 'sopra, in grassetto riporto le stringhe
Selection.AutoFilter Field:=6, Criteria1:=">=" & Format(Crituno, "mm/dd/yy"), Operator:= _
xlAnd, Criteria2:="<=" & Format(Critdue, "mm/dd/yy")
End Sub

Ringrazio Massimo Cannazza che con un suo esempio mi ha fatto capire che il problema stava nel formato data.

 

Buon lavoro.

prelevato sul sito http://ennius.interfree.it