You are on page 1of 60

All About The Tables

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!

Section Quick Links


 Excel Tables Overview
 Selecting Areas Of A Table With VBA
 Inserting Rows and Columns Into The Table
 Deleting Parts Of A Table
 Deleting/Clearing The Data In A Table
 Loop Through Each Table Column Or Row
 Looking Up Values Within A Table

 Apply A Sort Order To A Table Column


 Reading Table Data Into An Array Variable
 Resizing A Table
 Change All Table Column's Total Row Calculations
 Getting To The ActiveTable
 Additional Articles

Excel Tables Overview


What Is A Table?

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 Parts of A Table

The below infographic will help you visualize the different parts of a Table object through
the lens of the VBA coding language.

These parts of a ListObject Table include:

 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.

1. The Table Design Tab Appears

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.

2. The Blue Corner Indicator

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!

3. Use Excel’s Name Manager

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.

4. VBA Code To Check If Cell Is In A ListObject Table

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

Dim TestForTable As String

'Test To See If Cell Is Within A Table


  On Error Resume Next
  TestForTable = ActiveCell.ListObject.Name
  On Error GoTo 0

'Determine Results of Test


  If TestForTable <> "" Then
    'ActiveCell is within a ListObject Table
      MsgBox "Cell is part of the table named: " & TestForTable
  Else
    'ActiveCell is NOT within a ListObject Table
      MsgBox "Cell is not part of any table"
  End If

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.

Selecting Areas of a Table with VBA


Select VBA Coding
Entire Table ActiveSheet.ListObjects("Table1").Range.Select
Table Header
ActiveSheet.ListObjects("Table1").HeaderRowRange.Select
Row
Table Data ActiveSheet.ListObjects("Table1").DataBodyRange.Select
Third Column ActiveSheet.ListObjects("Table1").ListColumns(3).Range.Select
Third Column
ActiveSheet.ListObjects("Table1").ListColumns(3).DataBodyRange.Select
(Data Only)
Select Row 4
ActiveSheet.ListObjects("Table1").ListRows(4).Range.Select
of Table Data
Select 3rd
ActiveSheet.ListObjects("Table1").HeaderRowRange(3).Select
Heading
Select Data
point in Row 3, ActiveSheet.ListObjects("Table1").DataBodyRange(3, 2).Select
Column 2
Subtotals ActiveSheet.ListObjects("Table1").TotalsRowRange.Select

Inserting Rows and Columns into the Table


Select VBA Coding
Insert A New Column 4 ActiveSheet.ListObjects("Table1").ListColumns.Add Position:=4
Insert Column at End of
ActiveSheet.ListObjects("Table1").ListColumns.Add
Table
Insert Row Above Row
ActiveSheet.ListObjects("Table1").ListRows.Add (5)
5
Add Row To Bottom of ActiveSheet.ListObjects("Table1").ListRows.Add AlwaysInsert:=
Table True
Add Totals Row ActiveSheet.ListObjects("Table1").ShowTotals = True
Deleting Various Parts Of A Table
Sub RemovePartsOfTable()

Dim tbl As ListObject

Set tbl = ActiveSheet.ListObjects("Table1")

'Remove 3rd Column


  tbl.ListColumns(3).Delete

'Remove 4th DataBody Row


  tbl.ListRows(4).Delete

'Remove 3rd through 5th DataBody Rows


  tbl.Range.Rows("3:5").Delete

'Remove Totals Row


  tbl.TotalsRowRange.Delete

End Sub

Deleting/Clearing The Data In A Table


Delete all data rows from a table (except the first row)

Sub ResetTable()

Dim tbl As ListObject

Set tbl = ActiveSheet.ListObjects("Table1")

'Delete all table rows except first row


  With tbl.DataBodyRange
    If .Rows.Count > 1 Then
      .Offset(1, 0).Resize(.Rows.Count - 1, .Columns.Count).Rows.Delete
    End If
  End With

'Clear out data from first table row


  tbl.DataBodyRange.Rows(1).ClearContents

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()

Dim tbl As ListObject

Set tbl = ActiveSheet.ListObjects("Table1")

'Delete all table rows except first row


  With tbl.DataBodyRange
    If .Rows.Count > 1 Then
      .Offset(1, 0).Resize(.Rows.Count - 1, .Columns.Count).Rows.Delete
    End If
  End With

'Clear out data from first table row (retaining formulas)


  tbl.DataBodyRange.Rows(1).SpecialCells(xlCellTypeConstants).ClearContents

End Sub

Loop Through Each Table Column Or Row


Sub LoopingThroughTable()

Dim tbl As ListObject


Dim x As Long

Set tbl = ActiveSheet.ListObjects("Table1")

'Loop Through Each Column in Table


  For x = 1 To tbl.ListColumns.Count
    tbl.ListColumns(x).Range.ColumnWidth = 8
  Next x

'Loop Through Every Row in Table


  For x = 1 To tbl.Range.Rows.Count
    tbl.Range.Rows(x).RowHeight = 20
  Next x
  
'Loop Through Each DataBody Row in Table
  For x = 1 To tbl.ListRows.Count
    tbl.ListRows(x).Range.RowHeight = 15
  Next x

End Sub

Apply Sort To Column In A Table


You may find yourself needing to sort your Table data in either Ascending or Descending
order. The following VBA code will show you how to sort a column in your ListObject
Table in either order.

Sub SortTableColumn()
'PUPOSE: Sort Table in Ascending/Descending Order
'SOURCE: www.TheSpreadsheetGuru.com

Dim tbl As ListObject


Dim SortOrder As Integer

'Choose Sort Order


  SortOrder = xlAscending '(or xlDescending)

'Store Desired Excel Table to a variable


  Set tbl = ActiveSheet.ListObjects("Table1")

'Clear Any Prior Sorting


  tbl.Sort.SortFields.Clear
    
'Apply A Sort on Column 1 of Table
    tbl.Sort.SortFields.Add2 _
        Key:=tbl.ListColumns(1).Range, _
        SortOn:=xlSortOnValues, _
        Order:=SortOrder, _
        DataOption:=xlSortNormal
    
'Sort Options (if you want to change from default)
  tbl.Sort.Header = xlYes
  tbl.Sort.MatchCase = False
  tbl.Sort.Orientation = xlTopToBottom
  tbl.Sort.SortMethod = xlPinYin

'Apply the Sort to the Table


  tbl.Sort.Apply

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

Dim tbl As ListObject


Dim SortOrder As Integer

'Choose Sort Order


  SortOrder = xlDescending  '(or xlAscending)

'Store Desired Excel Table to a variable


  Set tbl = ActiveSheet.ListObjects("Table1")

'Clear Any Prior Sorting


  tbl.Sort.SortFields.Clear

'Apply A Sort on Column 1 of Table


    tbl.Sort.SortFields.Add2 _
        Key:=tbl.ListColumns(1).Range, _
        Order:=SortOrder

'Apply the Sort to the Table


  tbl.Sort.Apply

End Sub

Looking Up Values Within A Table


If you are storing values inside a Table, there may be scenarios where you wish to look up
or find a value. There are many different lookup scenarios one might have, but for
simplicity, I will provide a generic example. The following code looks to find an ID string
within a specific table’s first column and returns that ID’s table row number. Hopefully,
you can use the logic within this example and apply it to your specific needs.

Sub LookupTableValue()

Dim tbl As ListObject


Dim FoundCell As Range
Dim LookupValue As String

'Lookup Value
  LookupValue = "ID-123"

'Store Table Object to a variable


  Set tbl = ActiveSheet.ListObjects("Table1")

'Attempt to find value in Table's first Column


  On Error Resume Next
  Set FoundCell = tbl.DataBodyRange.Columns(1).Find(LookupValue, LookAt:=xlWhole)
  On Error GoTo 0

'Return Table Row number if value is found


  If Not FoundCell Is Nothing Then
    MsgBox "Found in table row: " & _
      tbl.ListRows(FoundCell.Row - tbl.HeaderRowRange.Row).Index
  Else
    MsgBox "Value not found"
  End If

End Sub

Store Table Data In An Array Variable


Pulling in data from tables is a great tactic to incorporate in your VBA coding.  Tables are
ideal because they:

 Are always structured the same


 Can be moved anywhere on the spreadsheet without affecting your code
 Automatically adjust their range size

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.

Single Column Table

Sub SingleColumnTable_To_Array()

Dim myTable As ListObject


Dim myArray As Variant
Dim TempArray As Variant
Dim x As Long

'Set path for Table variable


  Set myTable = ActiveSheet.ListObjects("Table1")

'Create Array List from Table


  TempArray = myTable.DataBodyRange
  
'Convert from vertical to horizontal array list
  myArray = Application.Transpose(TempArray)

'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

Multiple Column Table

Sub MultiColumnTable_To_Array()

Dim myTable As ListObject


Dim myArray As Variant
Dim x As Long

'Set path for Table variable


  Set myTable = ActiveSheet.ListObjects("Table1")

'Create Array List from Table


  myArray = myTable.DataBodyRange

'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.

(A special thanks to Peter Bartholomew for requesting this on LinkedIn)

Sub ResizeTable()

Dim rng As Range


Dim tbl As ListObject

'Resize Table to 7 rows and 5 columns


  Set rng = Range("Table1[#All]").Resize(7, 5)
  
  ActiveSheet.ListObjects("Table1").Resize rng
  
  
'Expand Table size by 10 rows
  Set tbl = ActiveSheet.ListObjects("Table1")
  
  Set rng = Range(tbl.Name & "[#All]").Resize(tbl.Range.Rows.Count + 10,
tbl.Range.Columns.Count)
  
  tbl.Resize rng

End Sub

Change All Table Total Row Calculations


Sub ChangeAllColumnTotals()

Dim tbl As ListObject


Dim CalcType As Integer
Dim x As Long

Set tbl = ActiveSheet.ListObjects("Table1")

'What calculation should the Totals Row Have?


  CalcType = 1 'or: xlTotalsCalculationSum

'Loop Through All Table Columns


  For x = 1 To tbl.ListColumns.Count
    tbl.ListColumns(x).TotalsCalculation = CalcType
  Next x
'___________________________________________
'Members of xlTotalsCalculation
    'Enum       Calculation
    ' 0           None
    ' 1           Sum
    ' 2           Average
    ' 3           Count
    ' 4           Count Numbers
    ' 5           Min
    ' 6           Max
    ' 7           Std Deviation
    ' 8           Var
    ' 9           Custom
'___________________________________________

End Sub

Getting the ActiveTable


There may be instances where you want to make a personal macro that formats your
selected table in a certain way or adds certain calculation columns.  Since the Excel
developers didn't create an ActiveTable command in their VBA language, you have no
straightforward way of manipulating a user-selected table.  But with a little creativity, you
can make your own ActiveTable ListObject variable and do whatever you want with the
selected table!

Sub DetermineActiveTable()

Dim SelectedCell As Range


Dim TableName As String
Dim ActiveTable As ListObject

Set SelectedCell = ActiveCell

'Determine if ActiveCell is inside a Table


  On Error GoTo NoTableSelected
    TableName = SelectedCell.ListObject.Name
    Set ActiveTable = ActiveSheet.ListObjects(TableName)
  On Error GoTo 0

'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

Visual Learner? Download My Example Workbook


Screenshot from one of the tabs in the downloadable file

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.  

Download Example Excel File


If you would like to get a copy of the Excel file I used throughout this article, feel free to
directly download the spreadsheet by clicking the download button below.

Download Example File

More Interesting Articles About Excel Tables


 Copy & Paste An Excel Table Into Microsoft Word With VBA
 Loop Through All Tables In Your Excel Workbook or Worksheet
 VBA to Populate Userform Combobox from Excel Table
 Insert & Delete Table Rows With Worksheet Protection
 Function To Determine If Column Heading Exists Inside Excel Table

Anything Else About Tables I Missed?


Did you come to this page trying to find out how to do something with VBA and Excel
tables and it wasn't covered? If that is the case, let me know what you were looking for in
the comment section below.  If it makes sense to add it to this guide and will definitely add
it to the content.  I look forward to reading your thoughts and/or recommendations!

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 :)

Set FoundCell = table.DataBodyRange.Columns(<tblcol>).Find(<lookupvalue>,


LookAt:=xlWhole, LookIn:=xlValues)

full function code below ==============

Private Function FindValueInTable(LookupValue As String, table As ListObject, TblCol


As Integer) As Boolean
Dim FoundCell As Range
FindValueInTable = False

On Error Resume Next


Set FoundCell = table.DataBodyRange.Columns(TblCol).Find(LookupValue,
LookAt:=xlWhole, LookIn:=xlValues)
If Not FoundCell Is Nothing Then FindValueInTable = True
On Error GoTo 0

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

 ¿Qué hace el objeto ListObject?


 ¿Cómo se crea un ListObject?
 Añadiendo una fila al ListObject
 Obtener la cantidad de filas de un ListObject
 Consultar un registro del ListObject
 Eliminar un registro del ListObject
 Aplicar auto filtro al ListObject
 Filtrar y ordenar por columna los datos del ListObject
o Filtrar y ordenar por columna
o Filtrar por criterio

¿Qué hace el objeto ListObject?


ListObject no es un simple objeto, en realidad es un conjunto de objetos que permiten
trabajar con una tabla de datos como si fuera una lista. Al tratar una tabla como lista, se
pueden manipular dichos datos de una manera mucho más sencilla y rápida. Los objetos
más importantes que forman parte de esta colección son:

 ListRow: Representa una fila de datos


 ListColumn: Representa una columna completa de da datos
 DataBodyRange: Representa la tabla completa de datos, pero sin los nombres de
las columnas.

¿Cómo se crea un ListObject?


Suponiendo que tenemos datos suficientes en una Hoja como para una tabla.
Lo primero que necesitamos es seleccionarlos.

En el menú Insertar, presionamos el botón Tabla.


En la ventana de diálogo llamada Crear tabla, nos aseguramos que marcar la opción La
tabla tiene encabezados, luego presionamos el botón Aceptar.

En el menú Diseño de tabla, damos un clic en la opción Nombre de la tabla y


reemplazamos el nombre default (Tabla1) por uno de nuestra preferencia. Al terminar
presionamos Enter en nuestro teclado.
Lo siguiente, es manipular el objeto por VBA. Para ello, necesitamos activar el modo
Programador (Puedes saltar esta parte si ya sabes como hacerlo) Para activar el modo
Programador, vamos a utilizar el botón Personalizar barra de herramientas de acceso
rápido, al abrirla, seleccionamos la opción Más comandos.

En la ventana de diálogo Opciones de Excel, seleccionamos la categoría Personalizar


cinta de opciones que se encuentra a la izquierda de la ventana. Después, marcamos la
opción Programador que se encuentra la opción Pestañas principales. Finalmente
presionamos Aceptar.
En el menú Programador, presionamos el botón Visual Basic. También podemos llegar
ahí al presionar Alt+F11

Al llegar a la ventana de Visual Basic, buscamos la sección Proyecto, ahí presionamos el


botón derecho del ratón sobre VBAProject. Una vez ahí, seleccionamos Insertar y
después Módulo.
Esta es la ventana de Módulo, como podemos ver a la izquierda, ahora tenemos una carpeta
llamada Módulos y dentro de ella nuestro módulo llamado Módulo1. Podemos tener tantos
como sea necesario, pero para nuestro ejercicio, con este basta. Notemos también que
nuestra única hoja se encuentra arriba agrupada dentro de Microsoft Excel Objects.
¡Es hora de programar! Creamos tres variables de ámbito Global, una de tipo ListObject
para manipular toda la tabla, otra de tipo ListRow para las operaciones con filas y una más
de tipo ListColumn para trabajar con las columnas.

1Global mitabla As ListObject


2Global mifila As ListRow
3Global micolumna As ListColumn

Nuestro módulo luce así por el momento.

Añadiendo una fila al ListObject


En una segunda hoja, preparamos todo el escenario para capturar un registro nuevo. Eso
incluye una forma rectangular que servirá de botón. Debe quedar como sigue. No hay que
olvidar preparar cada celda con su correspondiente formato. Incluso, se puede utilizar una
validación de datos si es necesario.
De regreso a Visual Basic, es hora de crear un procedimiento para insertar.

1Sub insertarFila()
2   ' Trabajaremos aquí dentro
3End Sub

Reemplacemos el comentario por el código que necesitamos. Lo primero será instanciar el


ListObject.

1Set mitabla = Hoja1.ListObjects("listado")

Luego, instanciamos el objeto ListRow y le pasamos como parámetro el método Add, de


esta forma podemos insertar rápidamente los elementos.

1Set mifila = mitabla.ListRows.Add


El objeto ListRow utiliza la colección Range, en este caso podemos listar las columnas en
lugar de la referencia, por ejemplo Range(1) se refiere a la columna 1 y así. Con eso en
mente, pasamos los datos de la segunda hoja a cada columna correspondiente.

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

Inmediatamente, limpiamos las celdas de la segunda hoja.

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

Dejamos de apuntar a la fila nueva al hacerla valer Nothing.

1Set mifila = Nothing

Y enviamos un mensaje de confirmación.

1MsgBox "El registro se ha insertado con éxito"

Nuestro código quedo como sigue.


De regreso a Excel, presionamos el botón derecho sobre la forma y elegimos la opción
Asignar Macro.
En la ventana Asignar macro, seleccionamos nuestra macro de la lista llamada Nombre de
la macro y presionamos el botón Aceptar.
Es hora de probar nuestro ejemplo.

Obtener la cantidad de filas de un ListObject


Lo siguiente que necesitamos saber, es como obtener la cantidad de filas que hay dentro del
objeto. Para lograr esto, necesitamos la constante Count que regresa precisamente este
valor. Dicha constante forma parte de la colección ListRows. Hagamos una función que
nos permita reutilizar este valor de tipo Integer.

1Function contarFilas() As Integer


2   'Trabajaremos aquí dentro
3End Function

Quitando el comentario, solo necesitamos dos líneas de código. Con la primera


instanciamos nuevamente el objeto ListObject que tenemos.

1Set mitabla = Hoja1.ListObjects("listado")

Con la segunda, obtenemos el valor de Count y lo mandamos de regreso al asignarlo a la


misma función

1contarFilas = mitabla.ListRows.Count

Nuestra función debe quedar así:


Con la función hecha, realizamos un procedimiento para poder invocarla dentro de Excel.
Este procedimiento regresara el valor de la función dentro de un mensaje, concatenado con
un poco de texto para que tenga algo de sentido. Recordemos que para concatenar un
Integer, tenemos la función Str que nos permite tratarlo como texto.

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.

Al presionar nuestro nuevo botón, esto es lo que obteemos.


Consultar un registro del ListObject
Para obtener un registro necesitamos hacer uso del objeto DataBodyRange que forma parte
de ListRows. Por supuesto necesitamos saber con certeza cuantos registros tiene nuestra
tabla. Afortunadamente eso ya lo sabemos, así que buscaremos dentro de la tabla.

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.

Damos un clic en la celda donde colocaremos el nombre del campo a utilizar. A


continuación, nos vamos al menú Datos y presionamos el botón Validación de datos.
En la sección Configuración de la ventana de Validación de datos, abrimos la lista
llamada Permitir y elegimos la opción Lista.

A continuación, en la sección Origen, escribiremos una fórmula de la siguiente manera: La


lista de campos se encuentra en la Hoja 1 desde A1 hasta F1, así que:

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.

Entonces, por ejemplo. Si seleccionamos el campo Neto y escribimos un valor, deberíamos


poder obtener el registro que coincide con esos parámetros. Por supuesto, es momento de
programar. En nuestro módulo, crearemos un nuevo procedimiento llamado buscarRegistro.

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

Ahora, crearemos múltiples variables de tipo Integer: La columna, la fila, la cantidad de


registros que hay, el id, cantidad y neto encontrados.

1Dim col, fil, hay, id, cantidad, neto As Integer

El precio se define como Currency (Moneda)

1Dim precio As Currency

Y una bandera tipo Boolean que nos indica si se puede localizar el registro (true) o no
(false).

1Dim exito As Boolean

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.

1If Len(Hoja2.Range("E6").Value) = 0 Or Len(Hoja2.Range("E7").Value) = 0


2Then
        MsgBox "El campo o el valor de la consulta no están disponibles"
3Else
4   'Aquí trabajaremos lo siguiente
5End If

Si nuestras celdas no se encuentran vacías (Else), podemos proceder a la búsqueda.


Primero, recuperamos la tabla con los datos. Recordemos que Set, nos permite
precisamente eso.

1Set mitabla = Hoja1.ListObjects("listado")

Recuperamos el campo que seleccionamos con la validación de datos.

1campo = Hoja2.Range("E6").Value

Y también el valor que escribimos.

1valor = Hoja2.Range("E7").Value

En el orden que tenemos en nuestra tabla, el campo ID es el primero, el campo Producto es


el segundo y así sucesivamente. Esto lo podemos hacer con If o con Select.

1If campo = "ID" Then col = 1


2If campo = "Producto" Then col = 2
If campo = "Cantidad" Then col = 3
3If campo = "Precio" Then col = 4
4
If campo = "Neto" Then col = 5
5If campo = "Medida" Then col = 6
6

Obtenemos la cantidad de filas que hay en nuestra tabla.

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.

1For fil = 1 To hay


2   'Trabajaremos aquí
3Next

Buscamos dentro de la tabla, usando el objeto DataBodyRange que represente


precisamente el contenido de la tabla. Como ya tenemos la columna y la fila, podemos
hacer lo siguiente:

1encontrado = mitabla.DataBodyRange(fil, col)

Si encontramos el valor que buscamos, activamos la bandera de éxito a True y terminamos


el ciclo For para evitar seguir buscando. En caso contrario, ponemos la bandera en False.

1If encontrado = valor Then


2   exito = True
3   Exit For
4Else
5   exito = False
End If
6

Si tuvimos éxito encontrando la fila…

1If exito Then

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

Una vez obtenido, enviamos el mensaje con el registro encontrado.

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:

Eliminar un registro del ListObject


Para eliminar un registro del objeto ListObject, solo necesitamos la colección ListRows
que contiene la tabla de datos pero en forma de fila. Comencemos con las variables que
necesitamos. Para esto, hemos construido en la Hoja2 lo siguiente.
En la celda C10, colocaremos la lista de ID de cada producto. Para que esto funcione y se
actualice con cada registro nuevo, haremos lo siguiente.

Nos cambiamos a la Hoja1, y en el menú Fórmulas, damos clic en Administrador de


nombres.
En la ventana de diálogo, presionamos el botón Nuevo.
En la siguiente ventana, escribiremos en la caja de Nombre, un nombre personalizado para
nuestra lista de IDs, en este caso llamaremos a nuestra lista: identificadores. una vez hecho
esto, en la sección Se refiere a, presionamos el botón con la flecha hacia arriba.

En nuestra tabla. seleccionamos únicamente los ID, sin incluir el título de la columna.

Observemos que listado[ID], representa la columna completa. Al presionar el botón con la


flecha abajo, regresamos a la ventana anterior y presionamos Aceptar.
De regreso a la primera ventana, simplemente presionamos el botón Cerrar.

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.

Con eso, ya podemos ver la lista de IDs en la celda.


¡Ahora, vamos a programar nuevamente!

En nuestro módulo, crearemos un procedimiento llamado eliminarRegistro.

1Sub eliminarRegistro()
2   'Trabajaremos aquí
3End Sub

Necesitamos el ID que queremos eliminar, la cantidad de filas, la fila donde encontramos el


valor y el ID encontrado para comparar. Todas estás son de tipo Integer.

1Dim delID, hay, fila, IDEncontrado As Integer

Una variable de tipo Boolean para saber si encontramos el ID

1Dim hallado As Boolean

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.

1Dim opcion As Variant

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.

1If Len(Hoja2.Range("C10").Value) = 0 Then


2        MsgBox "Por favor, seleccione el ID del producto a eliminar"
Else
3   'Aquí continuaremos trabajando lo que sigue
4End If
5

Si la celda no se encuentra vacía, entonces obtenemos la tabla:

1Set mitabla = Hoja1.ListObjects("listado")

Obtenemos el ID que seleccionamos en la celda C10 de la Hoja2.

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.

opcion = MsgBox("¿Desea eliminar el registro " + Str(delID) + "?",


1vbYesNo)

Y si presionamos el botón Sí (vbYes)

1If opcion = vbYes Then


2   ' Continuaremos trabajando aquí
3End If

Obtenemos la cantidad de filas que hay.

1hay = contarFilas

Con un ciclo For desde la primera fila hasta la cantidad máxima obtenida.

1For fila = 1 To hay


2   'Aquí va lo que sigue
3Next

Primero agarramos el ID de cada fila a través del DataBodyRange.

1IDEncontrado = mitabla.DataBodyRange(fila, 1)

Si el IDEncontrado es igual al ID para eliminar, entonces marcamos la bandera de hallado y


terminamos el For, en caso contrario solo marcamos la bandera como False y seguimos
buscando.

1If IDEncontrado = delID Then


2   hallado = True
3   Exit For
4Else
5   hallado = False
End If
6
Lo que sigue, va después de que termina el ciclo For. Es decir, si hallamos el ID que
queremos, entonces con ListRows y el número de la fila encontrada, lo eliminamos con el
método Delete, Enviamos el mensaje de éxito y limpiamos la celda C10 de la Hoja2. En
caso contrario (Else) enviamos el mensaje de que no se pudo eliminar el producto.

1If hallado Then


2   mitabla.ListRows(fila).Delete
3   MsgBox "Producto eliminado con éxito"
4   Hoja2.Range("C10").Value = ""
5Else
   MsgBox "No se ha encontrado el producto que deseaba eliminar"
6End If
7

El procedimiento completo, luce así:


Para ir cerrando esta parte, regresamos a la Hoja2 de Excel, tomamos la forma que creamos
a manera de botón. En ella, presionamos el botón derecho del ratón y elegimos Asignar
macro.

En la ventana de diálogo, seleccionamos nuestro procedimiento llamado eliminarRegistro y


presionamos Aceptar.

¡Es la hora de probar esto también!

Aplicar auto filtro al ListObject


Por supuesto, una de las mejores características de un ListObject es la capacidad de aplicar
filtros a la tabla de datos que representa. Con eso en mente, regresamos a la Hoja1 que
contiene la tabla y creamos algo como lo que sigue:

Ahora que ya tenemos el escenario preparado, vamos a crear nuestro un procedimiento en


nuestro módulo de Visual Basic que nos permita activar y desactivar los filtros.
Llamaremos a ese módulo filtrar.

1Sub filtrar()
2   'Trabajaremos aquí
3End Sub

Necesitamos una variable para el texto que tiene escrito el botón de “Desactivar filtro”

1Dim textoForma As String

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.

1Set mitabla = Hoja1.ListObjects("listado")


Si el texto de la forma dice “Activar filtro” hacemos que la tabla active el autofiltro
estableciendo la propiedad ShowAutoFilter a True y cambiamos el texto a “Desactivar
filtro”, de lo contrario cambiamos ese valor a False para desactivar y el texto de la forma lo
establecemos a “Activar filtro”.

1If textoForma = "Activar filtro" Then


2   mitabla.ShowAutoFilter = True
3   Hoja1.Shapes(1).TextFrame.Characters.Text = "Desactivar filtro"
4Else
5   mitabla.ShowAutoFilter = False
   Hoja1.Shapes(1).TextFrame.Characters.Text = "Activar filtro"
6End If
7

El procedimiento completo queda así:

De regreso a Excel, presionamos el botón derecho del ratón sobre la forma “Desactivar
filtro” y elegimos Asignar macro.

Seleccionamos el procedimiento filtrar y presionamos el botón Aceptar.


¡Veamos eso en acción!

Filtrar y ordenar por columna los datos del ListObject


Podemos filtrar y ordenar los datos por columna, para ello, utilizaremos el objeto Sort para
ordenar y AutoFilter para aplicar el filtro que queremos.

Filtrar y ordenar por columna

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.

Damos un clic en la opción Origen, específicamente en el botón con la flecha.


A continuación, seleccionamos únicamente los títulos de cada columna de la tabla, y
volvemos a presionar el mismo botón de la flecha.

Ahora, presionamos el botón Aceptar.


Con esto, ya podemos ver la lista de campos en dicha celda.

De regreso a Visual Basic, creamos un procedimiento llamado filtrarColumna.

1Sub filtrarColumna()
2   'Trabajaremos aquí
3End Sub

Necesitamos una variable para la columna de tipo String


1Dim columna As String

Ahora, capturamos el valor de la celda B11 en dicha variable.

1columna = Hoja1.Range("B11").Value

Si el valor estaba vacío entonces enviamos un mensaje notificando eso.

1If Len(columna) = 0 Then


2   MsgBox "Seleccione una columna para filtrar"

Y si no estaba vacío, entonces capturamos nuestra tabla.

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:

 Key; Es el rango de datos a filtrar. En nuestro caso lo pasaremos a través de Range


con el nombre de nuestro ListObject y la variable columna concatenados.
 SortOn: Define el criterio de ordenamiento, usaremos el valor default
xlSortOnValues que significa que utilizará valores directos.
 Order: puede ser: xlAscending (Ascendente) y xlDescending (Descendente)

La línea queda así:

mitabla.Sort.SortFields.Add Key:=Range("listado[" + columna + "]"),


1SortOn:=xlSortOnValues, Order:=xlAscending

Después le pedimos que excluya los encabezados del ordenamiento con la propiedad
Header.

1mitabla.Sort.Header = xlYes

Le pedimos con MatchCase en False que no compruebe repetidos (opcional)

1mitabla.Sort.MatchCase = False

Aplicamos el auto filtro.

1mitabla.Sort.Apply
Y cerramos el If que estaba abierto.

1End If

El código queda así:

De regreso a Excel, presionamos el botón derecho del ratón sobre el primer botón de
Aplicar y seleccionamos Asignar macro.

En la ventana de diálogo, seleccionamos nuestro procedimiento llamado filtrarColumna y


presionamos el botón Aceptar.
¡Hay que probar lo que acabamos de hacer!

Filtrar por criterio

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.

1Dim columna, criterio As String

Creamos una variable Boolean para saber si estamos en condiciones de aplicar el filtro.

1Dim filtrado As Boolean

Y el número de la columna que vamos a utilizar.

1Dim col As Integer


Lo primero será inicializar nuestra bandera a True, partiendo de que idealmente podemos
aplicar filtros.

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.

1If Len(columna) = 0 Then


2   MsgBox "Seleccione una columna para filtrar"
3   filtrado = False
4End If

El segundo caso sucederá si tenemos seleccionado el nombre de la columna, pero no hemos


escrito el criterio que queremos utilizar. Hacemos lo mismo, notificamos lo sucedido y
cambiamos la bandera a False.

1If Len(columna) > 0 And Len(criterio) = 0 Then


2   MsgBox "Escriba un criterio para el filtro"
3   filtrado = False
4End If

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.

1If filtrado Then


2   'Continuaremos trabajando aquí
3End If

Primero obtenemos el número de cada columna en base a su nombre. Esto lo podemos


hacer de muchas manera, aquí lo hice con If.

1If columna = "ID" Then col = 1


2If columna = "Producto" Then col = 2
3If columna = "Cantidad" Then col = 3
4If columna = "Precio" Then col = 4
5If columna = "Neto" Then col = 5
If columna = "Medida" Then col = 6
6

Recuperamos la tabla.

1Set mitabla = Hoja1.ListObjects("listado")


Desactivamos y enseguida reactivamos el auto filtro. Es un poco raro, pero sin eso a veces
no se actualiza la tabla de acuerdo a lo que elegimos.

1mitabla.ShowAutoFilter = False
2mitabla.ShowAutoFilter = True

Finalmente aplicamos el filtro usando dos atributos del objeto AutoFilter.

 Field: Es el número de la columna, aquí lo reemplazamos con la variable que


obtuvimos.
 Criteria1: Es el primer criterio para filtrar. Aquí pasamos la variable con la
información de nuestra celda B13.

1mitabla.Range.AutoFilter Field:=col, Criteria1:=criterio

El procedimiento completo queda así:

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.

Por supuesto, es momento de probar lo último.

Como podemos ver, el ListObject es un objeto muy útil y poderoso que puede tener un sin
fin de aplicaciones.

You might also like