Visto che questa mattina c'è troppo vento per godersi un'uscita in bici (c'è il rischio di essere spostati dalle raffiche in mezzo alla strada!!!!) ho cercato di rendere più veloce l'esposizione dei dati nella tabella pivot in base ai mesi desiderati.
L'utilizzo della proprietà Visible dei singoli Items è poco efficiente.
Anche facendo in modo che, mantendendo il precedente filtro, vengano nascosti i soli Items eventualmente visibili, comunque la procedura per un numero elevato di date impiega, da questo pc, qualche secondo. Se si parte da tutti gli Items visibili fino anche a 15".
Avevo provato a leggere l'articolo che Elio ha gentilmente indiato:
http://dailydoseofexcel.com/archives/2013/11/14/filtering-pivots-based-on-external-ranges/
ma evidentemente richiede qualche componente che io non ho (forse powerpivot).
Alcune variabili dichiarate nella cartella di lavoro di esempio dal mio pc vengono indicate come "Tipo definito dall'utente" (es. Dim sc As SlicerCache) e quindi, anche ove fossi riuscito a comprendere esattamente cosa veniva fatto non sarebbe stato utilizzabile.
Allora ho pensato ad una soluzione "casareccia".
Una procedura che in base ai mesi inseriti crei una matrice, (ho utilizzato una funzione esterna alla routine che esegue il "filtro") di dati relativi solo a quelle date relative a quei mesi, riporti questi dati, con le relative identiche intestazioni in un'altra sezione del foglio (o volendo anche in un apposito foglio dedicato) questi dati e assegni quell'intervallo alla PivotCache.
Se la cella dedicata al primo mese è vuoto viene utilizzato l'intervallo originario per impostare la cache della tabella pivot.
Se viene compilata al cella del solo mese iniziale viene creato un nuovo intervallo con le sole date di quel mese.
Se viene compilata anche la cella del mese finale viene creato un nuovo intervallo con le date che vanno dal mese iniziale a quello finale.
Ho anche cercato di replicare il "comportamento" dei filtri della tabella pivot nel caso tutte le voci del campo Autore, a cui corrisponde un dettaglio relativo al Tipo di documento acquistato, siano compresse o "espanse" o solo alcune compresse e altre espanse.
Per fare questo mi sono affidato ad una dictionary dove memorizzo gli Items degli Autori prima di modificare la Cache e ad una funzione "esterna" che verifica se tutte le voci sono compresse o meno.
Il tutto più o meno in meno di mezzo secondo che quindi è molto più accettabile, soprattutto rispetto ai quasi 15" nel caso di primo filtro rispetto alla situazione di nessun filtro.
Qui, per eventuale vostra curiosità, il file con le ultime modifiche:
https://www.dropbox.com/s/1sdhvw59wn8feij/Vendite%20Tabella%20Pivot%202018%233.xlsm?dl=0
Nel Modulo4 sono presenti le routine e le function utilizzate per gestire il "filtro".
Nel Modulo5 una routine che imposta la tabella pivot in automatico partendo dalla "pulizia" della tabella alla reipostazione dei campi e formati da me desiderati per questa tabella (così ne ho approfittato per studiare un po' gli oggetti della tabella pivot in vba).
Riporto di seguito il codice relativo alla gestione del filtro presenti nel modulo4:
'---
Public Const iColonnaDateAutori As Long = 1
Public Const sNomeWsDatiVendite As String = "Dati Vendite Documenti"
Public Const sPrimaCellaDatiVendite = "A1"
Public Const sNomeWsPivot As String = "Pivot Vendite Documenti"
Public Const sNomeWsFiltroPivot As String = sNomeWsDatiVendite '"FiltroPivot"
Public Const sPrimaCellaFiltroPivot As String = "AA1"
Sub ImpostaPivotCacheConFiltroMesi()
'Dim iTimer As Double: iTimer = Timer
Dim Twb As Workbook
Dim WsDatiVendite As Worksheet
Dim PrimaCellaDatiVendite As Range
Dim IntervalloDatiVendite As Range
Dim IntervalloIntestazioni As Range
Dim iColonneDatiVendite As Long
Dim WsPivot As Worksheet
Dim pvtTable As PivotTable
Dim pvtItem As PivotItem
Dim StatoItemsShowDetail As Object
Dim cMeseIniziale As Range
Dim cMeseFinale As Range
Dim WsFiltroPivot As Worksheet
Dim PrimaCellaFiltroPivot As Range
Dim iMeseIniziale As Long
Dim iMeseFinale As Long
Dim arrDatiVendite As Variant
Dim arrDatiFiltrati As Variant
Dim sSourceData As String
Dim bAggiornaPivotCache As Boolean
Dim bAggiornaPivotCacheII As Boolean
Dim bpvtFieldShowDetail As Boolean
Set Twb = ThisWorkbook
With Twb
Set WsDatiVendite = .Worksheets(sNomeWsDatiVendite)
Set WsPivot = .Worksheets(sNomeWsPivot)
Set WsFiltroPivot = .Worksheets(sNomeWsFiltroPivot)
End With
Set PrimaCellaDatiVendite = WsDatiVendite.Range(sPrimaCellaDatiVendite)
With WsPivot
Set cMeseIniziale = .Range("MeseIniziale")
Set cMeseFinale = .Range("MeseFinale")
iMeseIniziale = cMeseIniziale.Value
iMeseFinale = cMeseFinale.Value
Set pvtTable = .PivotTables(1)
End With
With WsFiltroPivot
Set PrimaCellaFiltroPivot = .Range(sPrimaCellaFiltroPivot)
PrimaCellaFiltroPivot.CurrentRegion.Clear
End With
With PrimaCellaDatiVendite
With .CurrentRegion
If .Rows.Count >= 2 Then
Set IntervalloDatiVendite = .Cells
Set IntervalloIntestazioni = .Rows(1)
iColonneDatiVendite = IntervalloIntestazioni.Columns.Count
arrDatiVendite = .Cells.Offset(1, 0).Resize(.Rows.Count - 1).Value2
bAggiornaPivotCache = True
End If
End With
End With
If bAggiornaPivotCache Then
If iMeseIniziale = 0 Then
sSourceData = IntervalloDatiVendite.Address(True, True, xlA1, True)
If cMeseFinale.Value > 0 Then cMeseFinale.ClearContents
bAggiornaPivotCacheII = True
ElseIf iMeseIniziale > 0 Then
If iMeseFinale = 0 Then
arrDatiFiltrati = ArrFiltroPivot(arrDatiVendite, iMeseIniziale)
ElseIf iMeseFinale > 0 Then
arrDatiFiltrati = ArrFiltroPivot(arrDatiVendite, iMeseIniziale, iMeseFinale)
End If 'iMeseFinale
If Not IsEmpty(arrDatiFiltrati) Then
bAggiornaPivotCacheII = True
With PrimaCellaFiltroPivot
.Offset(0, 0).Resize(, iColonneDatiVendite).Value = IntervalloIntestazioni.Value
With .Offset(1, 0).Resize(UBound(arrDatiFiltrati, 1), iColonneDatiVendite)
.Value = arrDatiFiltrati
.Columns(1).NumberFormat = "dd/mm/yyyy"
'.IndentLevel = 1
End With
sSourceData = .CurrentRegion.Address(True, True, xlA1, True)
End With
End If 'Not IsEmpty(arrDatiFiltrati)
End If 'iMeseIniziale
If bAggiornaPivotCacheII Then
bpvtFieldShowDetail = bItemsShowDetail
Set StatoItemsShowDetail = CreateObject("Scripting.Dictionary")
With pvtTable
For Each pvtItem In .PivotFields("Autore").PivotItems
With pvtItem
StatoItemsShowDetail.Add .Name, .ShowDetail
End With
Next pvtItem
.ManualUpdate = True
.ClearAllFilters
.ChangePivotCache Twb.PivotCaches.Create(SourceType:=xlDatabase, _
SourceData:=sSourceData, _
Version:=xlPivotTableVersion12)
With .PivotCache
.RefreshOnFileOpen = True
.MissingItemsLimit = xlMissingItemsNone
.Refresh
End With
.RefreshTable
For Each pvtItem In .PivotFields("Autore").PivotItems
With pvtItem
If Not StatoItemsShowDetail.Exists(.Name) Then
.ShowDetail = bpvtFieldShowDetail 'False
'.ShowDetail = False
End If
End With
Next pvtItem
.ManualUpdate = False
Set StatoItemsShowDetail = Nothing
End With 'pvtTable
Else
cMeseIniziale.ClearContents
cMeseFinale.ClearContents
Call ImpostaPivotCacheConFiltroMesi
End If 'bAggiornaPivotCacheII
End If 'bAggiornaPivotCache
'Debug.Print Timer - iTimer
End Sub
Function ArrFiltroPivot(arrDati As Variant, _
MeseIniziale As Long, _
Optional MeseFinale As Long = 0) As Variant
Dim i As Long, j As Long, cont As Long
Dim arrTmp() As Variant
Dim arrTrasposta() As Variant
For i = 1 To UBound(arrDati, 1)
If MeseFinale = 0 Then
If Month(arrDati(i, iColonnaDateAutori)) = MeseIniziale Then
cont = cont + 1
For j = 1 To UBound(arrDati, 2)
ReDim Preserve arrTmp(1 To UBound(arrDati, 2), 1 To cont)
arrTmp(j, cont) = arrDati(i, j)
Next j
End If
Else
If Month(arrDati(i, iColonnaDateAutori)) >= MeseIniziale And _
Month(arrDati(i, iColonnaDateAutori)) <= MeseFinale Then
cont = cont + 1
For j = 1 To UBound(arrDati, 2)
ReDim Preserve arrTmp(1 To UBound(arrDati, 2), 1 To cont)
arrTmp(j, cont) = arrDati(i, j)
Next j
End If
End If 'MeseFinale
Next i
If cont > 0 Then
ReDim arrTrasposta(1 To UBound(arrTmp, 2), 1 To UBound(arrTmp, 1))
For i = 1 To UBound(arrTmp, 2)
For j = 1 To UBound(arrTmp, 1)
arrTrasposta(i, j) = arrTmp(j, i)
Next j
Next i
ArrFiltroPivot = arrTrasposta
End If 'cont > 0
End Function
Function bItemsShowDetail() As Boolean
Dim pvtItem As PivotItem
Dim bShowDetail As Boolean
bShowDetail = True
With ThisWorkbook.Worksheets(sNomeWsPivot)
With .PivotTables(1).PivotFields("Autore")
For Each pvtItem In .PivotItems
If Not pvtItem.ShowDetail Then
bShowDetail = False
Exit For
End If
Next pvtItem
End With
End With
bItemsShowDetail = bShowDetail
End Function
'---
Diciamo che meglio di così non saprei come ottenere il risultato dei filtri in maniera piuttosto veloce.
Forse ci sarà da effettuare qualche aggiustamento nel caso in cui l'archivio dei dati sia vuoto per evitare errori ma eventualmente con l'uso verranno fuori le magagne e cercherò di sistemare :)
Buona domenica ... ventosissima!!!