Lavorare con le tabelle di Excel
Scorri per mostrare il menu
Una tabella di Excel — ciò che VBA chiama un ListObject — è un intervallo denominato e auto-espandibile con frecce di filtro integrate, righe alternate e riferimenti strutturati alle colonne. Se i tuoi dati non sono già una Tabella, seleziona una qualsiasi cella al suo interno e premi Ctrl+T, oppure lascia che VBA ne crei una utilizzando ListObjects.Add.
Riferimento a un ListObject
Dim ws As Worksheet
Dim tbl As ListObject
Set ws = ThisWorkbook.Worksheets("Reports")
Set tbl = ws.ListObjects("tblReports")
Debug.Print tbl.Range.Address ' full table including header
Debug.Print tbl.DataBodyRange.Rows.Count ' data rows only, no header
Dichiarare tbl As ListObject (anziché solo As Range) è ciò che sblocca tutte le funzionalità specifiche delle Tabelle utilizzate nel resto di questa sezione — ListRows, ListColumns e la Total Row derivano tutte dal fatto che l'oggetto sia tipizzato correttamente. Nota la distinzione tra le due righe di Debug.Print:
tbl.Range copre l'intera Tabella inclusa la riga di intestazione, mentre tbl.DataBodyRange copre solo i dati sottostanti. '
Quasi tutte le operazioni — aggiungere una riga, sommare una colonna, scorrere i record — dovrebbero utilizzare DataBodyRange, proprio perché non si vuole che il testo dell'intestazione venga trattato accidentalmente come una riga dati.
Aggiunta di righe
ListRows.Add aggiunge una nuova riga direttamente sotto la tabella — e, cosa fondamentale, tutte le formule con riferimenti strutturati presenti nelle altre colonne si estendono automaticamente anche su di essa, uno dei maggiori vantaggi pratici di una Tabella rispetto a un intervallo semplice.
Dim newRow As ListRow
Set newRow = tbl.ListRows.Add
newRow.Range(1, 1).Value = "April"
newRow.Range(1, 2).Value = "North"
newRow.Range(1, 3).Value = 45200
newRow.Range(1, 4).Value = 30750
newRow.Range(1, 5).Value = 14450
newRow.Range(1, 6).Value = 41000
tbl.ListRows.Add crea la riga vuota e la restituisce come oggetto ListRow, motivo per cui le sei righe successive scrivono su newRow invece che su tbl. newRow.Range(1, 1) significa "riga 1 di questa specifica nuova riga, colonna 1" — l'indicizzazione riparte da 1 per la nuova riga stessa, non conta dall'inizio della tabella. Questa è una pratica decisamente migliore rispetto a trovare l'ultima riga del foglio con End(xlUp) e scrivere manualmente una colonna oltre: ListRows.Add si posiziona sempre correttamente all'interno dei confini della Tabella, quindi qualsiasi Riga Totale, formula con riferimento strutturato o regola di formattazione condizionale applicata alla Tabella si estende automaticamente per includerla.
Aggiornamento dei record
Per aggiornare una riga esistente, scorrere DataBodyRange e confrontare una colonna chiave — qui, aggiornando il Target della regione Central di febbraio dopo una revisione del budget:
Dim r As Long
For r = 1 To tbl.DataBodyRange.Rows.Count
If tbl.DataBodyRange.Cells(r, 1).Value = "February" And _
tbl.DataBodyRange.Cells(r, 2).Value = "Central" Then
tbl.DataBodyRange.Cells(r, 6).Value = 52000 ' revised Target
Exit For
End If
Next r
Questo è lo stesso schema dall'alto verso il basso, fermandosi alla prima corrispondenza, tipico della logica condizionale, applicato a righe reali invece che a valori hardcoded: il ciclo controlla Mese e Regione insieme con And, e nel momento in cui entrambi corrispondono, aggiorna la colonna Target e chiama Exit For per non continuare a scansionare inutilmente le righe rimanenti. Utilizzare tbl.DataBodyRange.Cells(r, 1) invece di un riferimento Cells a livello di foglio mantiene la numerazione delle righe limitata ai soli dati della Tabella — la riga 1 qui significa la prima riga dati, indipendentemente da quale riga fisica del foglio inizi la Tabella.
Riferimento alle colonne della Tabella
I riferimenti strutturati — ListColumns("Name") — sono più leggibili e più robusti rispetto al conteggio delle colonne per numero, soprattutto quando una tabella viene modificata e le colonne si spostano:
Dim profitCol As Range
Set profitCol = tbl.ListColumns("Profit").DataBodyRange
Debug.Print Application.WorksheetFunction.Sum(profitCol)
Debug.Print Application.WorksheetFunction.Average(profitCol)
ListColumns("Profit") trova la colonna tramite il suo testo di intestazione invece che tramite la posizione, quindi il codice continua a funzionare anche se Profit viene successivamente spostata dalla colonna E alla colonna F — contare manualmente Cells(r, 5) si romperebbe silenziosamente in quel caso. Application.WorksheetFunction è il ponte che permette a VBA di richiamare direttamente le normali funzioni di Excel come SOMMA e MEDIA su un oggetto Range, invece di scrivere manualmente un ciclo con un totale progressivo, che richiederebbe più codice e sarebbe più soggetto a errori di conteggio.
Attività
- Aprire
Section_4_Reports.xlsx, salvarlo comeSection_4_Reports.xlsme confermare che i dati del foglio Reports siano una Tabella chiamatatblReports(cliccare su una qualsiasi cella al suo interno — dovrebbe apparire la scheda Progettazione tabella). - Scrivere una macro che aggiunga una riga di aprile per ognuna delle cinque regioni utilizzando
ListRows.Add(in totale cinque nuove righe, valori inventati vanno bene). - Scrivere una seconda macro che utilizzi
ListColumns("Sales").DataBodyRangeeWorksheetFunction.Sumper stampare il totale delle vendite di tutte le righe nella Finestra Immediata.
1. Apertura e conferma della Tabella
- Basta salvare nuovamente con File → Salva con nome, scegliendo "Cartella di lavoro con attivazione macro di Excel (*.xlsm)" dal menu a discesa del formato — nessun codice necessario per questa parte.
- Cliccare su una qualsiasi cella all'interno dei dati Reports e controllare che nella barra multifunzione appaia la scheda Progettazione tabella — questo conferma che si tratta di una vera Tabella di Excel, non solo di un intervallo che le somiglia.
2. Aggiunta di cinque righe di aprile con ListRows.Add
- Serve una variabile
ListObjectche punti atblReports, poi chiamare.ListRows.Adduna volta per ogni regione — cinque chiamate separate, oppure un ciclo che si ripete cinque volte. - Ogni nuova riga necessita di sei valori: Mese, Regione, Vendite, Spese, Profitto, Obiettivo — si fa riferimento alle posizioni (
newRow.Range(1, 1),(1, 2), ecc.), come nell'esempio pratico del Capitolo 4. - Un array con i nomi delle cinque regioni rende il ciclo più pulito rispetto a scrivere cinque blocchi quasi identici a mano.
3. Somma delle vendite con WorksheetFunction
ListColumns("Sales")trova la colonna tramite il suo nome di intestazione —.DataBodyRangerestringe la selezione solo alle celle dei dati, senza includere l'intestazione.Application.WorksheetFunction.Sum(...)accetta direttamente quell'intervallo — nessun ciclo necessario.Debug.Printinvia il risultato alla Finestra Immediata (Ctrl+G) invece che in un popup.
Option Explicit
Sub AddAprilRows()
Dim tbl As ListObject
Dim newRow As ListRow
Dim regions As Variant
Dim i As Long
Set tbl = ThisWorkbook.Worksheets("Reports").ListObjects("tblReports")
regions = Array("North", "South", "East", "West", "Central")
For i = 0 To 4
Set newRow = tbl.ListRows.Add
newRow.Range(1, 1).Value = "April"
newRow.Range(1, 2).Value = regions(i)
newRow.Range(1, 3).Value = 46000 + i * 500 ' Sales — invented
newRow.Range(1, 4).Value = 31000 + i * 300 ' Expenses — invented
newRow.Range(1, 5).Value = 15000 + i * 200 ' Profit — invented
newRow.Range(1, 6).Value = 41000 ' Target — invented
Next i
End Sub
Sub PrintTotalSales()
Dim tbl As ListObject
Dim salesCol As Range
Set tbl = ThisWorkbook.Worksheets("Reports").ListObjects("tblReports")
Set salesCol = tbl.ListColumns("Sales").DataBodyRange
Debug.Print "Total Sales: " & Application.WorksheetFunction.Sum(salesCol)
End Sub
Eseguire prima AddAprilRows, poi PrintTotalSales — il totale includerà automaticamente le cinque nuove righe di aprile, poiché DataBodyRange riflette sempre la dimensione attuale della Tabella.
Grazie per i tuoi commenti!
Chieda ad AI
Chieda ad AI
Chieda pure quello che desidera o provi una delle domande suggerite per iniziare la nostra conversazione