Probado en: Excel 365 v2509 · Excel 2021 · Excel 2019 · última verificación 12/06/2026
En resumen — Hay dos formas de llamar a VLOOKUP (BUSCARV en el Excel en español) desde VBA, y la diferencia decide si un valor ausente hace fallar tu macro. Application.WorksheetFunction.VLookup lanza un error de ejecución cuando no encuentra el valor; Application.VLookup (sin WorksheetFunction) devuelve un valor de error que compruebas con IsError. Y en cuanto recorres miles de filas, la respuesta correcta no suele ser ninguna de las dos — es un Dictionary.
Sub VLookupTwoWays()
Dim tbl As Range
Set tbl = Sheet1.Range("A:B")
' (1) WorksheetFunction — FALLA (error 1004) si "Acme" no está
Debug.Print Application.WorksheetFunction.VLookup("Acme", tbl, 2, False)
' (2) Application — devuelve un VALOR DE ERROR si no lo encuentra, sin fallar
Dim r As Variant
r = Application.VLookup("Ghost", tbl, 2, False)
If IsError(r) Then Debug.Print "no encontrado" Else Debug.Print r
End Sub
El modelo mental: VLOOKUP es una función de hoja de visita en VBA
VLOOKUP se diseñó para vivir en una celda. Al llamarlo desde VBA tomas prestada una función de hoja — y ese préstamo trae dos condiciones de las que ninguna fórmula de celda te avisa: cómo se comporta cuando el valor falta, y lo mal que escala cuando lo llamas en un bucle. Mantén esa imagen y las dos trampas de este artículo dejan de ser sorpresas.
Así que la primera pregunta no es «¿cómo escribo VLOOKUP en VBA?» — esa es la parte fácil, una línea. La pregunta real es cuál VLOOKUP, porque VBA expone dos con comportamiento de error opuesto, y luego si deberías llamarlo siquiera en cuanto entra un bucle.
La única regla: WorksheetFunction.VLookup falla, Application.VLookup devuelve un error
Esta es la distinción tras el problema de VBA VLOOKUP más reportado — el temido error de ejecución 1004 «No se puede obtener la propiedad VLookup»:
Llamado por
WorksheetFunction, un valor ausente lanza un error de ejecución que detiene en seco tu macro. Llamado directamente porApplication, un valor ausente vuelve como un valor de error (comoError 2042) que compruebas conIsError— sin fallo.
Ninguno es «el correcto»; son herramientas para dos situaciones. Usa WorksheetFunction cuando un valor ausente sea de verdad un bug y quieras que la macro pare (o lo hayas envuelto en On Error). Usa Application.VLookup cuando «no encontrado» sea un resultado normal y esperado que quieres tratar con elegancia.
' (A) WorksheetFunction + On Error — parar o bifurcar ante un error real
Dim price As Double
On Error Resume Next
price = Application.WorksheetFunction.VLookup(code, tbl, 2, False)
If Err.Number <> 0 Then
price = 0 ' valor por defecto, y seguimos
Err.Clear
End If
On Error GoTo 0
' (B) Application.VLookup + IsError — el patrón más limpio para "puede faltar"
Dim res As Variant
res = Application.VLookup(code, tbl, 2, False)
If IsError(res) Then price = 0 Else price = res
El patrón (B) se lee mejor y no secuestra el manejo de errores para el flujo normal — recurre a Application.VLookup siempre que un fallo sea esperado. (Mira VBA On Error sobre por qué un On Error Resume Next disperso es un lastre.)
La trampa que de verdad cuesta: VLOOKUP dentro de un bucle es O(n²)
Aquí está la que los tutoriales se saltan. Un solo VLOOKUP recorre la columna de búsqueda hasta hallar una coincidencia. Mete esa llamada en un bucle sobre tus filas y vuelves a recorrer toda la columna en cada iteración:
' ⚠ LENTO — 10.000 filas, cada una buscando en una tabla de 10.000 filas.
' Hasta 100.000.000 de comparaciones, y relee la hoja en cada pasada.
Dim i As Long
For i = 2 To 10000
Cells(i, "C").Value = Application.WorksheetFunction.VLookup( _
Cells(i, "A").Value, Sheet2.Range("A:B"), 2, False)
Next i
Es trabajo cuadrático, y con datos reales convierte «¿por qué está colgada mi macro?» en una pausa para el café de varios minutos. El número de comparaciones crece con el cuadrado del número de filas — el doble de filas, el cuádruple de espera.
La solución es dejar de buscar una y otra vez. Lee la tabla de búsqueda una vez en un Dictionary — es una tabla hash, así que cada acceso es O(1) en vez de O(n) — y todo el trabajo se vuelve lineal:
Sub LookupConDictionary()
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
' Leer ambas columnas a memoria de UNA vez — mira VBA Array, por qué importa
Dim lookup As Variant
lookup = Sheet2.Range("A2:B10000").Value
Dim i As Long
For i = 1 To UBound(lookup, 1)
dict(lookup(i, 1)) = lookup(i, 2) ' clave = columna A, valor = columna B
Next i
' Leer las claves, resolver en memoria, reescribir de UNA vez
Dim keys As Variant, out() As Variant, n As Long
keys = Sheet1.Range("A2:A10000").Value
n = UBound(keys, 1)
ReDim out(1 To n, 1 To 1)
For i = 1 To n
If dict.Exists(keys(i, 1)) Then out(i, 1) = dict(keys(i, 1)) Else out(i, 1) = "n/d"
Next i
Sheet1.Range("C2").Resize(n, 1).Value = out ' una escritura, no 10.000
End Sub
Mismo resultado, pero lee la hoja dos veces en lugar de 20.000, y el cotejo es por hash. En 10.000 filas es la diferencia entre «al instante» y «ve a por un café». (La otra mitad de la mejora — leer y escribir arrays de una vez en lugar de celda por celda — es un hábito aparte que merece la pena.)
Cuándo usar cuál
| Tu situación | Usa | Por qué |
|---|---|---|
| Búsqueda única, el valor siempre debería existir | WorksheetFunction.VLookup |
Un fallo es un bug — deja que se lance |
| Búsqueda única, el valor puede faltar | Application.VLookup + IsError |
Tratar «no encontrado» sin On Error |
| Buscar muchas filas contra una tabla | Un Dictionary construido una vez | O(1) en vez de O(n) por búsqueda |
| Quieres la posición de fila, no un valor | Application.Match |
VLOOKUP no devuelve una dirección |
| La columna de búsqueda está a la izquierda del resultado | Index/Match o un Dictionary |
VLOOKUP solo mira a la derecha |
La opinión: si llamas a VLOOKUP en un bucle, en realidad quieres un Dictionary
La línea que defiendo: VLOOKUP pertenece a las celdas, no a los bucles. Llamar una función de hoja una vez desde VBA para coger un solo valor está perfectamente bien. En cuanto está dentro de un bucle For sobre tus datos, has pedido a una operación diseñada para una búsqueda que recorra una columna miles de veces — y lo notarás.
El reflejo de «usa VLOOKUP sin más, ya lo conozco» es justo lo que mantiene lentas las macros. La jugada profesional es reconocer la forma del problema: muchas búsquedas contra una tabla es para lo que existe un Dictionary. Construye la tabla en memoria una vez, resuelve cada fila contra ella, reescribe las respuestas de una vez. Tu macro pasa de cuadrática a lineal, y el código para hacerlo es más corto que el manejo de errores que envolverías si no alrededor de un VLOOKUP en bucle.
Errores comunes de VBA VLOOKUP (y la solución)
| Síntoma | Causa | Solución |
|---|---|---|
| Error 1004 «No se puede obtener la propiedad VLookup» | WorksheetFunction.VLookup no halló el valor |
Application.VLookup + IsError, o envolver en On Error |
| La macro se cuelga con muchos datos | VLOOKUP llamado en un bucle de filas (O(n²)) | Construir un Dictionary una vez, resolver en memoria |
| Devuelve el valor equivocado | 4.º argumento omitido → coincidencia aproximada por defecto | Pasar siempre False para coincidencia exacta |
#N/D aunque el valor está ahí |
La columna de búsqueda tiene espacios / Chr(160) al final |
Limpiar la clave primero — mira VBA Trim |
| No puede buscar hacia la izquierda | VLOOKUP solo busca en la primera columna, hacia la derecha | Index/Match o un Dictionary |
| Discrepancia de tipos al guardar el resultado | El resultado puede ser un valor de error | Guardar en un Variant, comprobar IsError antes de usar |
Cuando las búsquedas se acumulan — describe el cruce en su lugar
No querías un debate sobre WorksheetFunction contra Application. Querías «cruza el export de este mes con mi lista de precios y marca los códigos que no existen». Para cuando has elegido el VLOOKUP correcto, protegido los fallos y reescrito el bucle como Dictionary para que termine esta década, la fontanería es la macro. ExcelMaster Agent te deja describir el cruce en español sencillo — «busca cada código de la columna A en la hoja de precios, pon el precio en C y lista los que no tengan coincidencia» — y escribe Python que lo hace todo en una pasada, haciendo antes una copia de seguridad de tu libro. Pruébalo gratis →
Guías relacionadas
- VBA Dictionary — búsquedas O(1) en memoria
- VBA Array — leer y escribir un rango de una vez
- VBA Copy Paste — evita el portapapeles para macros más rápidas
- VBA On Error — Resume Next vs GoTo y por qué las macros ocultan bugs
- VBA bucle For en Excel — 8 ejemplos reales
FAQ
¿Cómo se usa VLOOKUP en VBA?
Llámalo por el objeto application: Application.WorksheetFunction.VLookup(valorBuscado, rangoTabla, índiceColumna, False). Pasa siempre False como cuarto argumento para una coincidencia exacta. Si el valor puede faltar, usa Application.VLookup (sin WorksheetFunction) y comprueba el resultado con IsError, para que un fallo devuelva un valor de error en vez de hacer fallar la macro.
¿Por qué VBA VLOOKUP da el error de ejecución 1004?
Porque lo llamaste por WorksheetFunction y el valor no se encontró — esa vía lanza un error en vez de devolver #N/D. O envuelves la llamada en On Error Resume Next y compruebas Err.Number, o usas Application.VLookup, que devuelve un valor de error comprobable que tratas con If IsError(resultado).
¿Cuál es la diferencia entre Application.VLookup y WorksheetFunction.VLookup?
Hacen la misma búsqueda pero fallan distinto. WorksheetFunction.VLookup lanza un error de ejecución si nada coincide; Application.VLookup devuelve un valor de error (como Error 2042) que compruebas con IsError. Usa WorksheetFunction cuando un fallo sea un bug real, y Application cuando «no encontrado» sea esperado.
¿Es VLOOKUP lento en VBA?
Una sola llamada está bien. Llamarlo en un bucle sobre muchas filas es lento porque cada llamada vuelve a recorrer la columna de búsqueda, y el trabajo crece con el cuadrado del número de filas. Para muchas búsquedas, carga la tabla en un Scripting.Dictionary una vez y resuelve cada fila en O(1) — mucho más rápido con muchos datos.
¿Puede VBA VLOOKUP buscar un valor en otra hoja?
Sí — cualifica el rango de la tabla con la hoja: Application.WorksheetFunction.VLookup(clave, Worksheets("Precios").Range("A:B"), 2, False). Usa una referencia plenamente cualificada Worksheets("nombre").Range(...) para que la búsqueda no lea por accidente la hoja activa.
