Professional Documents
Culture Documents
For a data analyst, Excel Tables are a necessity! They are the most efficient way to
organize your raw data and refer to data that contracts or expands on a regular basis.
Likewise, Excel tables can be extremely useful in combination with VBA.
I personally use data tables as a way to store user settings without having to modify any
VBA code. You can see examples of this in my Exporter Template where I use tables to
store worksheet names and email addresses.
In this article, I wanted to bring all the common ways of referencing table data with VBA
into one place. Hopefully, this will serve as a guide you can come back to again and again
so you can easily and efficiently incorporate tables into your VBA macro coding. Enjoy!
A Table is simply a structured range where you can refer to different sections that are
automatically mapped out (such as the Header Row or the column below the header
"Amount"). Tables are an amazing feature that Microsoft added into Excel because they not
only structure your data, but they also expand with your data as it grows. And if there is one
thing you should know about creating a spreadsheet, it would be that making it as
DYNAMIC as possible is always a good thing!
You can quickly create a Table by highlighting a range (with proper headings) and using
the keyboard shortcut Ctrl + t. You can also navigate to the Insert tab and select the Table
button within the Tables group.
The below infographic will help you visualize the different parts of a Table object through
the lens of the VBA coding language.
Range
HeaderRowRange
DataBodyRange
ListRows
ListColumns
TotalsRowRange
How Do I Find Existing Tables?
Tables can be a little tricky to find if you are not familiar working with them because they
can blend in very well with the spreadsheet depending on the formatting that has been
applied.
Let’s look at 4 different ways you can determine if you are working with cells in a Table
Object.
If you click within a cell that is part of an Excel Table, you will immediately see the Table
Design tab appear in the Ribbon. This is a contextual tab, which means it only appears
when a specific object is selected on your spreadsheet (a similar tab appears when Pivot
Tables or Shapes are selected on a spreadsheet).
This is a very quick tell-tail sign that the cell you are working on is part of a Table Object.
There is a small little indicator at the bottom right cell of a Table range to indicate there is a
table. As you can see in the image below, this indicator can be very simple to find, but also
can be easily missed due to its small size!
Another great way to find a table (and its name) is to go into the Name Manager. You can
get to the name manager by navigating to the Formulas tab and clicking the Name
Manager button inside the Defined Names group.
By using the Filter menu in the right-hand corner of the Name Manager, you can narrow
down your name list to just the Tables within the Workbook. The Name Manager will
show you exactly where the tables are within the spreadsheet and also what the Table
names are.
There may be instances when you need to determine if a certain cell resides within a
ListObject (Table). The below VBA code shows you how you can perform a test to see if
the ActiveCell (selected cell) is part of any Excel Table on the spreadsheet.
Sub IsActiveCellInTable()
'PURPOSE: Determine if the current selected cell is part of an Excel Table
'SOURCE: www.TheSpreadsheetGuru.com
End Sub
This is a great validation test if you are creating code that allows the user to manipulate an
excel table. I’ve used this many times to create buttons that allow users to insert or delete
specific rows within a table based on where they select on a password protected sheet.
End Sub
Sub ResetTable()
End Sub
If you have formulas in your table, you may want to keep those intact. The following
modification will just remove constant values from the remaining first row in the Table
Object.
Sub ResetTable()
End Sub
End Sub
Sub SortTableColumn()
'PUPOSE: Sort Table in Ascending/Descending Order
'SOURCE: www.TheSpreadsheetGuru.com
End Sub
While the above VBA code has all the potential options written out for you to tweak, most
of the time you will not need to stray away from the default sorting options.
Below is the same code, but with all the options you likely don’t need to change from their
default setting value removed.
Sub SortTableColumn_Simple()
'PUPOSE: Sort Table in Ascending/Descending Order
'SOURCE: www.TheSpreadsheetGuru.com
End Sub
Sub LookupTableValue()
'Lookup Value
LookupValue = "ID-123"
End Sub
One example of using Tables as a data source in a macro is shown in one of my Code Vault
snippets which allows you to filter your data based on the words in a specified table.
There are tons of different ways you can use tables to store settings and preferences
dynamically for your macros. The below code shows you how to load in data from a single
column and a multi-column table.
Sub SingleColumnTable_To_Array()
'Loop through each item in the Table Array (displayed in Immediate Window [ctrl + g])
For x = LBound(myArray) To UBound(myArray)
Debug.Print myArray(x)
Next x
End Sub
Sub MultiColumnTable_To_Array()
'Loop through each item in Third Column of Table (displayed in Immediate Window [ctrl +
g])
For x = LBound(myArray) To UBound(myArray)
Debug.Print myArray(x, 3)
Next x
End Sub
Resizing A Table
If needed, you can resize a table's dimensions by declaring a new range area for the Excel
table to shrink or expand. Below are a couple of examples showing how you can perform
this sort of size adjustment.
Sub ResizeTable()
End Sub
End Sub
Sub DetermineActiveTable()
'Do something with your table variable (ie Add a row to the bottom of the ActiveTable)
ActiveTable.ListRows.Add AlwaysInsert:=True
Exit Sub
'Error Handling
NoTableSelected:
MsgBox "There is no Table currently selected!", vbCritical
End Sub
After many requests, I put together a fun little interactive workbook that will show you how
a bunch of the code described in this article actually works on a spreadsheet. It also serves
as a good reference that you can save to your computer so you don't have to keep googling
about Excel Tables whenever something slips your mind.
TIPS
I had a right head scratcher regarding Looking Up Values Within a Table
table.DataBodyRange.Columns(<tblcol>).Find(<lookupvalue>)
Does not seem to work if the column is calculated , I've not found a way around this yet
apart from
not using calculated values (I think it's using the calculation formula in the list rather than
the result of the formula)
UPDATE
about 30 seconds after posting the above adding Lookin:=xlValues sorted my issue
might be worth updating / sharing :)
End Function
El objeto ListObject nos permite manipular las tablas básicas que se pueden generar en
Excel. La ventaja de hacerlo a través de VBA, es que podemos utilizarlo para crear un
CRUD completo o una consulta personalizada de datos que puede llegar a ser incluso más
útil que una tabla dinámica si lo sabemos usar ¿Listo para comenzar a trabajar? ¡Manos a la
obra!
Tabla de Contenido
1Sub insertarFila()
2 ' Trabajaremos aquí dentro
3End Sub
1mifila.Range(1) = Hoja2.Range("B1").Value
2mifila.Range(2) = Hoja2.Range("B2").Value
3mifila.Range(3) = Hoja2.Range("B3").Value
4mifila.Range(4) = Hoja2.Range("B4").Value
5mifila.Range(5) = Hoja2.Range("B5").Value
mifila.Range(6) = Hoja2.Range("B6").Value
6
1Hoja2.Range("B1").Value = ""
2Hoja2.Range("B2").Value = ""
3Hoja2.Range("B3").Value = ""
4Hoja2.Range("B4").Value = ""
5Hoja2.Range("B5").Value = ""
Hoja2.Range("B6").Value = ""
6
1contarFilas = mitabla.ListRows.Count
1Sub cuantos()
2 MsgBox "Hay" + Str(contarFilas) + " registros"
3End Sub
De regreso en Excel, colocamos una segunda forma para usarla como botón.
Presionamos el botón derecho sobre esa forma y seleccionamos la opción Asignar macro
nuevamente.
En la ventana de diálogo, seleccionamos nuestro procedimiento que hicimos para contar y
presionamos el botón Aceptar.
Para hacer la búsqueda más interesante, hemos creado en la segunda hoja un espacio para
elegir el campo que queremos usar como criterio de búsqueda y el valor a utilizar. Por
supuesto, también hemos colocado una forma para que sea el botón que realice todo.
1=Hoja1!$A$1:$F$1
Nótese que esta escrito en valor absoluto para asegurarnos que se use específicamente esa
lista. Al terminar, presionamos el botón Aceptar.
Nuestra lista muestra ahora los campos que tenemos disponibles.
1Sub buscarRegistro()
2 'Trabajaremos aquí dentro
3End Sub
Primero, necesitamos múltiples variables de tipo String: El nombre del campo, el registro
encontrado, el valor escrito, el nombre del producto y la unidad de medida.
1Dim campo, registro, valor, encontrado, producto, medida As String
Y una bandera tipo Boolean que nos indica si se puede localizar el registro (true) o no
(false).
Lo siguiente, es validar que las celdas en la hoja 2 que utilizaremos para la consulta no se
encuentren vacías, ya que en caso de estarlo, necesitamos enviar un mensaje al usuario para
notificarle. La función Len permite obtener la longitud de caracteres de un elemento.
1campo = Hoja2.Range("E6").Value
1valor = Hoja2.Range("E7").Value
1hay = contarFilas
Podemos revisar la tabla con un ciclo, en este caso usaremos un For que empiece en la fila
1 y termine en el valor que nos entregue la variable hay.
Llenamos las variables que creamos para cada campo, con la fila que encontramos (variable
fil) en el DataBodyRange y la columna correspondiente (Id = 1, producto = 2, etc…)
1id = mitabla.DataBodyRange(fil, 1)
2producto = mitabla.DataBodyRange(fil, 2)
3cantidad = mitabla.DataBodyRange(fil, 3)
4precio = mitabla.DataBodyRange(fil, 4)
5neto = mitabla.DataBodyRange(fil, 5)
medida = mitabla.DataBodyRange(fil, 6)
6
Finalmente, vamos a crear un mensaje con todo el registro completo. Concatenaremos todo
lo encontrado en nuestra variable llamada registro y con vbCrLf nos aseguramos de hacer
saltos de línea para que no aparezca todo junto. No olvidemos utilizar Str en las variables
que no sean String.
1
registro = "Hemos encontrado lo siguiente:" + vbCrLf
2registro = registro + "ID:" + Str(id) + vbCrLf
3registro = registro + "Producto:" + producto + vbCrLf
4registro = registro + "Cantidad:" + Str(cantidad) + vbCrLf
5registro = registro + "Precio:" + Str(precio) + vbCrLf
6registro = registro + "Cont. Neto:" + Str(neto) + vbCrLf
registro = registro + "Medida:" + medida + vbCrLf
7registro = registro + "Fila del registro:" + Str(fil)
8
1MsgBox registro
Agregamos el Else que falta para enviar un mensaje en caso de no encontrar ningún
registro, y cerramos el If.
1Else
2 MsgBox "No se ha encontrado registro coincidente"
3End If
Como ya fue mucho código, aquí tienes el procedimiento completo por si estas un poco
enredado.
Por supuesto, necesitamos que eso funcione en Excel, así que regresamos a la Hoja2 donde
estamos trabajando y con el botón derecho del ratón sobre la forma Buscar Registro,
elegimos la opción Asignar Macro.
En el cuadro de diálogo, seleccionamos la macro llamada buscarRegistro y presionamos el
botón Aceptar.
Probemos el resultado de todo ese trabajo:
En nuestra tabla. seleccionamos únicamente los ID, sin incluir el título de la columna.
De regreso a la Hoja2, damos clic en la celda que vamos a utilizar (C10), luego vamos al
menú Datos y presionamos Validación de datos.
En la ventana de diálogo, damos click en la opción Permitir y elegimos Lista.
En la opción Origen, escribimos la fórmula:
1=identificadores
Notemos que es el nombre personalizado que creamos hace unos momentos. Al finalizar,
presionamos el botón Aceptar.
1Sub eliminarRegistro()
2 'Trabajaremos aquí
3End Sub
También necesitamos una variable de tipo Variant que nos permite elegir entre Sí y No, ya
que preguntaremos antes de eliminar. Además los botones en VBA son precisamente de ese
tipo.
Revisaremos con Len si la celda C10 de la Hoja2 se encuentra vacía o no. En caso de estar
vacía enviaremos un mensaje para notificar.
1delID = Hoja2.Range("C10").Value
Creamos una ventana de diálogo con MsgBox al añadir como segundo parámetro la opción
vbYesNo que representa los botones Sí y No.
1hay = contarFilas
Con un ciclo For desde la primera fila hasta la cantidad máxima obtenida.
1IDEncontrado = mitabla.DataBodyRange(fila, 1)
1Sub filtrar()
2 'Trabajaremos aquí
3End Sub
Necesitamos una variable para el texto que tiene escrito el botón de “Desactivar filtro”
Todas las formas que coloquemos en nuestra hoja de Excel, forman parte de la colección
Shapes, la cuál básicamente es un vector. La propiedad Text forma parte del objeto
Characters de la sub colección TextFrame.
1textoForma = Hoja1.Shapes(1).TextFrame.Characters.Text
En mi caso, la forma que estoy usando casualmente era la primera de la lista. También
recuperamos la tabla otra vez.
De regreso a Excel, presionamos el botón derecho del ratón sobre la forma “Desactivar
filtro” y elegimos Asignar macro.
En la celda B11 de nuestra Hoja colocaremos la lista completa e los campos de nuestra
tabla. Para ello, seleccionamos dicha celda, vamos al menú Datos y presionamos el botón
Validación de datos.
En la ventana de diálogo, abrimos la opción Permitir, y elegimos Lista.
1Sub filtrarColumna()
2 'Trabajaremos aquí
3End Sub
1columna = Hoja1.Range("B11").Value
1Else
2 Set mitabla = Hoja1.ListObjects("listado")
A través de la colección Sort y del Objeto SortFields, limpiamos con el método Clear
cualquier filtro anterior.
1mitabla.Sort.SortFields.Clear
Para crear el filtro utilizaremos el método Add de SortFields, este método necesita como
mínimo 3 elementos:
Después le pedimos que excluya los encabezados del ordenamiento con la propiedad
Header.
1mitabla.Sort.Header = xlYes
1mitabla.Sort.MatchCase = False
1mitabla.Sort.Apply
Y cerramos el If que estaba abierto.
1End If
De regreso a Excel, presionamos el botón derecho del ratón sobre el primer botón de
Aplicar y seleccionamos Asignar macro.
Ahora que ya filtramos por columna, podemos añadir un criterio básico para mejorar el
filtro. Utilizaremos la celda B13 para escribir cualquier criterio para filtrar nuestra tabla y
utilizaremos por supuesto la columna seleccionada en B11. Así que regresando a Visual
Basic, creamos nuestro último procedimiento llamado filtrarCriterio.
1Sub filtrarCriterio()
2 'Trabajaremos aquí
3End Sub
Necesitamos 2 variables de tipo String, una para la columna y otra para el criterio ya que el
ListObject recibe los criterios como cadenas de texto.
Creamos una variable Boolean para saber si estamos en condiciones de aplicar el filtro.
1filtrado = True
Tenemos dos posibles casos donde la bandera puede cambiar a False, el primero es si no
tenemos seleccionado el nombre de la columna en B11, así que enviamos el mensaje
notificando lo sucedido y por supuesto cambiamos la bandera a Flase.
Los demás posibles casos serán lidiados por la validación de datos. Si quieres saber como
utilizarla, recuerda que ya hablamos de ella hace tiempo. Si la bandera nunca cambio a
False, sino que se quedo en True, entonces podemos aplicar el filtro.
Recuperamos la tabla.
1mitabla.ShowAutoFilter = False
2mitabla.ShowAutoFilter = True
De regreso a Excel, presionamos el botón derecho del ratón sobre el segundo botón de
Aplicar en nuestra Hoja1 y seleccionamos Asignar macro.
En la ventana de diálogo, seleccionamos nuestro procedimiento llamado filtrarCriterio y
presionamos el botón Aceptar.
Como podemos ver, el ListObject es un objeto muy útil y poderoso que puede tener un sin
fin de aplicaciones.