5 Formas de crear rangos dinámicos VBA Excel.

Hola y bienvenidos a una entrada más, hoy vamos a darle una checada a 5 formas en las que podrás crear tus rangos dinámicos en vba excel

Imagínate que no sabes mucho de VBA, usas la grabadora para copiar un rango de celdas y hacer alguna acción con el (copiar, poner un filtro, crear una tabla dinámica, convertir el rango en tabla).

Todo salió de maravilla y cuando quieres volverla a usar con un rango más grande te das cuenta de que no funciona del todo bien.  ¿La razón?  El rango que seleccionaste con la grabadora queda como un rango fijo, por lo que ahora es necesario crear un rango que se ajuste a tus necesidades.

Aquí abajo te dejo algunos ejemplos que como hacerlo sin romperte mucho la cabeza.

  1. Forma 1. UsedRange
  2. Forma 2. Ultima Fila – Columna de la hoja con xlUp.
  3. Forma 3. xlTypeLastCell
  4. Forma 4. CurrentRegion.
  5. Forma 5. Contar el número de filas – columnas.

Forma 1. UsedRange

El método UsedRange nos permite seleccionar un rango en una hoja que ya haya sido activado anteriormente.

Sub PruebaRangos()

'Establece primero la hoja a usar y la celda de inicio
 Dim sht As Worksheet
 Set sht = Sheets(1)
 sht.Select

' Método 1 UsedRange
' Efectivo cuando el proceso es automático y no hay mas datos en la hoja
 sht.UsedRange.Select

End Sub       
  • Pros: Es un método veloz, de hecho, el mas veloz como veremos en la tabla de abajo.
  • Contras: Solo funciona si tu rango a seleccionar es el único valor en la hoja, si hay datos mas abajo o mas a la derecha también los copiara.

Forma 2. Ultima Fila – Columna de la hoja con xlUp.

Este método te permitirá almacenar en una variable la ultima fila y la ultima columna del rango de tu hoja. Es un método un poco más lento que el anterior, pero mas efectivo ya que depende de donde posicionemos nuestra celda de inicio.

Sub PruebaRangos()
Dim sht As Worksheet
Dim LRow, LCol As Long
Dim StartCell As Range

' Establece primero la hoja a usar y la celda de inicio
Set sht = Sheets(1)
sht.Select
Set StartCell = Range("A1")

'Metodo 2 Ultima fila - columna
' Efectivo cuando la tabla esta distribuida equitativamente
  LRow = sht.Cells(sht.Rows.Count, StartCell.Column).End(xlUp).Row
  LColumn = sht.Cells(StartCell.Row, sht.Columns.Count).End(xlToLeft).Column
  sht.Range(StartCell, sht.Cells(LRow, LColumn)).Select

End Sub
  • Pros: Menor margen de error que el método UsedRange ya que permite definir a partir de donde tomar los valores
  • Contras: Debemos conocer la posición inicial del rango, además de que, si la primera celda de ultima fila o de la ultima columna esta en blanco, el código no leerá el rango apropiadamente.

Forma 3. xlTypeLastCell

Con la propiedad SpecialCells del método Range podremos ir automáticamente a la ultima fila y columna sin la necesidad de que están tengan valores propiamente, como pasaba arriba.

Sub PruebaRangos()
Dim sht As Worksheet
Dim LRow, LCol As Long
Dim StartCell As Range

' Establece primero la hoja a usar y la celda de inicio
Set sht = Sheets(1)
sht.Select
Set StartCell = Range("A1")

'Metodo 3 ultima celda
'Efectivo cuando quieres todos los valores de una hoja de calculo.
   LRow = StartCell.SpecialCells(xlCellTypeLastCell).Row
   LColumn = StartCell.SpecialCells(xlCellTypeLastCell).Column
   sht.Range(StartCell, sht.Cells(LRow, LColumn)).Select

End Sub
  • Pros:   Nos dirige automáticamente a la ultima celda que este activa y toma su fila – columna de forma más rápida. Ideal si los usuarios no pueden depositar datos de forma manual en la hoja a usar.
  • Contras: Es el método mas lento de los aquí descritos, además de que conlleva que una celda mas abajo o mas a la derecha no haya sido activada, lo que puede ocasionar algunos detalles.

Forma 4. CurrentRegion.

La propiedad CurrentRegion nos permite dejar a Excel tratar de identificar la relación que existe entre los valores que queremos tomar como rango. Esto funciona especialmente bien si el rango es una tabla o tiene ya filtros delimitados.

Sub PruebaRangos()
Dim sht As Worksheet
Dim StartCell As Range

' Establece primero la hoja a usar y la celda de inicio
Set sht = Sheets(1)
sht.Select
Set StartCell = Range("A1")

' Metodo 4 Current Region
' Efectivo cuando no tenemos filas o columnas en blanco y el rango esta definido por una tabla
      StartCell.CurrentRegion.Select

End Sub
  • Pros: Funciona desde cualquier parte del rango relacionado, evitando tener que saber en que parte se inicia el rango.
  • Contras: Si buscas colocar filtros o tienes filas – columnas en blanco el método fallara inevitablemente.

Forma 5. Contar el número de filas – columnas.

Incluyo este ya que en lo particular es con el que aprendí a programar cuando empecé con mis pininos en VBA, y me parece hoy en día un método con versatilidad ya que nos puede decir cuál es el largo y ancho de nuestros valores y podemos usar eso en algunas itinerancias con el ciclo For.

Sub PruebaRangos()
Dim sht As Worksheet
Dim rng, rng2 As Long
Dim StartCell As Range

' Establece primero la hoja a usar y la celda de inicio
Set sht = Sheets(1)
sht.Select
Set StartCell = Range("A1")

'Metodo 5
' Efectivo para copiar y pegar en ciertos rangos que pueden variar y mantener guardado el largo y ancho
    rng = Application.WorksheetFunction.CountA(Range("A1:A1000000")) - 1
    rng2 = Application.WorksheetFunction.CountA(Range("1:1")) - 1
    Range(StartCell, StartCell.Offset(rng, rng2)).Select

End Sub
  • Pros: Es un método estable, el que menos variación presento de velocidad en la prueba que hice, adicional de que permite conocer exactamente el largo y ancho de nuestros valores.
  • Contras: Al igual que cualquier método de formula de Excel, si los datos tienen valores en blanco en alguna fila – columna, puede generar errores.

EL MEJOR DE ELLOS…

El ultimo, ¡Obvio!

Bueno, no. En realidad, todos funcionan dependiendo tus necesidades y el escenario de tus datos. Si nos vamos a una prueba de velocidades al parecer los primeros dos métodos son los más veloces. La prueba se realizo con un rango de 10000 celdas en la cual las macros copiaban y pegaban los valores en una hoja.

rango_dinamico_vba_excel
Tiempo de funcionamiento de cada macro, en segundos

Una recomendación adicional, utiliza siempre Application.ScreenUpdating antes de cualquier macro, el tiempo de reacción se mejora en promedio en un 75%.

rangos_dinamicos_vba_excel1
Tiempo de funcionamiento de cada macro con ScreenUpdating, en segundos.

Si tienes alguna duda sobre rangos dinámicos en vba excel, nos leemos abajo.

5 Formas de crear rangos dinámicos VBA Excel.

25 comentarios en «5 Formas de crear rangos dinámicos VBA Excel.»

  1. Cordial saludo, muchas gracias por compartir tu conocimiento, gracias a ti he aprendido mucho de powerapps y powerautomate.

    Tengo una consulta ¿Cómo convierto el rango seleccionado en una tabla? lo he intentado pero no me da.

    1. hola.
      Para crear una tabla en vba puedes usar esto.
      Set src = Range(«B5:B10″)
      Set ws = ActiveSheet
      ws.ListObjects.Add( SourceType:=xlSrcRange, Source:=src, _
      xlListObjectHasHeaders:=xlYes, tablestyleName:=»TableStyleMedium28»).Name = «TuTabla»

  2. Hola, estas formas están muy bien, pero, ¿qué ocurre si el número de filas o de columnas es cambiante, y no sé dónde va a empezar o terminar el rango?. Mi problema es que quiero insertar valores desde VBA a una columna cuyo encabezado es el día del mes, pero la tabla no tiene los fines de semana, y el día 5 no siempre estará en posición 5. Lo que quiero hacer es muy simple: Cómo indicar a VBA que quiero insertar un dato en la celda cuyo encabezado es, por ejemplo, «MARTES», ó «DÍA 5», y cuya fila sea el ID de una persona, por ejemplo, «PEPITO02».
    ¿Es posible hacer esto que digo?, llevo dos días buscando en webs inglesas y en español y no encuentro nada, pese a que encuentro que para muchos informes que tengo que hacer es muy necesario.
    Muchas gracias!

    1. Hola.
      Hay varias formas de hacer eso, yo creo que la mas funcional es.
      1. En la fila de los encabezados crea un do Until para revisar valor por valor de la celda
      2. cuando encuentres el valor terminar tu Do y guardas el Rango en una celda tipo Range.
      3. Con esto ya sabes donde empezar y creas tu procedimiento hacia las filas.

  3. Hola, estas formas están muy bien, pero, ¿qué ocurre si el número de filas o de columnas es cambiante, y no sé dónde va a empezar o terminar el rango?. Mi problema es que quiero insertar valores desde VBA a una columna cuyo encabezado es el día del mes, pero la tabla no tiene los fines de semana, y el día 5 no siempre estará en posición 5. Lo que quiero hacer es muy simple: Cómo indicar a VBA que quiero insertar un dato en la celda cuyo encabezado es, por ejemplo, «MARTES», ó «DÍA 5», y cuya fila sea el ID de una persona, por ejemplo, «PEPITO02».
    ¿Es posible hacer esto que digo?, llevo dos días buscando en webs inglesas y en español y no encuentro nada, pese a que encuentro que para muchos informes que tengo que hacer es muy necesario.
    Muchas gracias!

    1. Hola.
      Hay varias formas de hacer eso, yo creo que la mas funcional es.
      1. En la fila de los encabezados crea un do Until para revisar valor por valor de la celda
      2. cuando encuentres el valor terminar tu Do y guardas el Rango en una celda tipo Range.
      3. Con esto ya sabes donde empezar y creas tu procedimiento hacia las filas.

  4. Buenas tardes, estoy haciendo un ejercicio de compras pero presenta sub totales, estuve implementando formulas normales aunque he trabajado un poco con vba pero no llego al resultado

    ARTICULO (CONCEPTO) FECHA CANTIDAD VALOR TOTAL 5%COMISION
    ZELLE $ 1900,00
    PRESTOBARBA MAX 3 330 $ 2,95 $ 973,50 $ 48,68
    DESODORANTE SPEED STICK 390 $ 1,00 $ 390,00 $ 19,50
    ELEVADOR DE OCTANAJE 272 $ 1,07 $ 291,04 $ 14,55
    TOTAL aquí suma total
    ZELLE $ 2000,00
    VITAMINA C 1000 MG 60 $ 13,99 $ 839,40 $ 41,97
    SPLENDA 1200 SOBRES 35 $ 13,99 $ 489,65 $ 24,48
    FASCILISTAS KRAFT 96 UN 32 $ 6,29 $ 201,28 $ 10,06
    VITAMINA SOBRE 90 UN 5 $ 15,79 $ 78,95 $ 3,95
    TOTAL
    ZELLE $ 1500,00
    REPUESTOS MAX 3X5X4 36 $ 31,01 $ 1116,36 $ 55,82
    total crédito $ 739,31
    TOTAL
    ZELLE 26/08/2021 $ 3000,00

    La idea es que me sume los totales (para tener subtotales por cada compra) que estén dentro de los rangos «ZELLE» y «TOTAL», entre ellos puede haber cualquier cantidad de compras y como se puede ver, en la misma tabla existen varias compras que inician agregando un valor de «ZELLE» y debería totalizar al agregar la palabra «TOTAL» en la primera columna.

  5. Tengo una duda, estoy usando el metodo 5 pero no he logrado que me seleccione y copie toda la tabla, solo lo esta haciendo para la primera columna. En ese caso cual seria el codigo?

    1. Hola Juan.
      Con el metodo 5, tus columnas estan en la fila 1?
      Ya que este metodo cuenta cuantas columnas con valores tienes dentro del rango que le digas (en mi ejemplo 1:1 es todo lo de la primera fila)

      Checa que tengas el rango correcto y con valores y vuelve a probar
      Saludos!

  6. Hola
    Soy una aprendiz de VBA y estoy en un proyecto para crear un cotizador de Hoteles (Son muchos hoteles). Estos, tiene tarifas variables en diferentes periodos, y de acuerdo al tipo de habitación. Entonces he creado una que me genera los periodos y los inserta en la hoja del hotel correspondiente. En la columna de las fechas (dias) de ese periodo, la macro funciona perfectamente con cada período que genero. Sin embargo, yo necesito que los valores tarifas, se copien desde la Hoja llamada CrearPeriodo hasta la hoja del hotel.
    La hoja del Hotel cuando se crea tambien desde una macro en una hoja llamada CrearHotel, queda con un nombre determinado por la concatenación de dos celdas. Entonces supongamos que este se llama Maloka Standar.

    En otra hoja CrearPeriodo se introducen los datos para crear el periodo en la hoja creada desde CrearHotel

    A1 Titulo Crear Periodo Hotel
    C1 Nombre del Hotel (Se establece solo al correr la macro que crea esta Hoja)
    A2 Desde (El usuario indica fecha inicial por ejemplo 15/01/2022)
    A3 Hasta Desde (El usuario indica fecha final por ejemplo 30/01/2022)
    A4 Individual (El usuario indica Tarifa, por ejemplo $75)
    A5 Doble (El usuario indica Tarifa, por ejemplo $60)
    A6 Triple (El usuario indica Tarifa, por ejemplo $60)
    A7 Cuadruple (El usuario indica Tarifa, por ejemplo $60)
    A8 Quintuple (El usuario indica Tarifa, por ejemplo $60)
    A9 Niños (El usuario indica Tarifa, por ejemplo $30)
    A10 Infantes (El usuario indica Tarifa, por ejemplo $10)

    Al correr la macro, de generar periodo este hace un AutoFill y copia la serie de fechas en la columna A. y se posiciona en la ultima fila e la columna A para esperar la creación de otro periodo.
    Ahora requiero, y no tengo idea de como hacerlo que las tarifas tambien se copien en el mismo rango que ocupe cada periodo.

    Fecha Individual/Doble/Triple /Cuadruple/Quintuple/ Adicional/ Niño/ Infante
    15/01/2021 75 / 60/ 60
    16/01/2021 75 / 60/ 60
    17/01/2021 75 / 60/ 60

    30/01/2021 75 / 60 / 60

    Aquí la macro

    Sub Periodo()

    Dim Desde As Date
    Dim Hasta As Date
    Dim Hotel As String
    Dim Habitación As String
    Dim TarifaIndividual As Currency
    Dim TarifaDoble As Currency
    Dim TarifaTriple As Currency
    Dim TarifaCuadruple As Currency
    Dim TarifaQuintuple As Currency
    Dim TarifaNiño As Currency
    Dim TarifaInfante As Currency
    Dim Periodo As Variant
    Dim RangoPeriodo As Variant
    Dim xName As String

    Hotel = Sheets(«CrearHotel»).Range(«B1»)
    Habitación = Sheets(«CrearHotel»).Range(«B2»)
    Desde = Sheets(«CrearPeriodo»).Range(«B2»)
    Hasta = Sheets(«CrearPeriodo»).Range(«B3»)
    TarifaIndividual = Sheets(«CrearPeriodo»).Range(«B4»)
    TarifaDoble = Sheets(«CrearPeriodo»).Range(«B5»)
    TarifaTriple = Sheets(«CrearPeriodo»).Range(«B6»)
    TarifaCuadruple = Sheets(«CrearPeriodo»).Range(«B7»)
    TarifaQuintuple = Sheets(«CrearPeriodo»).Range(«B8»)
    TarifaNiño = Sheets(«CrearPeriodo»).Range(«B9»)
    TarifaInfante = Sheets(«CrearPeriodo»).Range(«B10»)
    Periodo = DateDiff(«d», Desde, Hasta) + 1
    dias = DateDiff(«d», Desde, Hasta) + 1
    xName = Sheets(«CrearPeriodo»).Range(«C1»)
    ActiveWorkbook.Sheets(xName).Select
    Rango = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row
    RangoPeriodo = ActiveSheet.Range(«A4»)

    Range(«A4»).Select

    Do While ActiveCell Empty

    ActiveCell.Offset(1, 0).Select

    Loop

    With ActiveCell
    Rango = .Resize(dias, 1).Address
    .Value = Desde
    .AutoFill Destination:=Range(Rango), Type:=xlFillSeries

    End With
    End Sub

  7. Hola, muchas gracias por la información.

    Me ha servido bastante, ahora estoy tratando de darle un nombre al rango definido en Excel para usarlo en una lista desplegable.

    Alguna idea de cómo?

    De antemano muchas gracias

    1. Hola Diana.
      Dependiendo del método que uses, tienes que pasar el rango con el método Names.Add
      Un ejemplo es.

      ThisWorkbook.Names.Add Name:=»Hola», RefersTo:=ThisWorkbook.Sheets(1).Range(«A1:A10»), Visible:=True

      Saludos.

  8. hola alguno me podria ayudar con esto:

    Range(Cells(2, 1), Cells(sw, 6)).Select

    ActiveSheet.ListObjects.Add(xlSrcRange, Range(«$A$2:$F$5»), , xlYes).Name = _
    «Tabla1»

    quiero hacer que en lugar de F5 se la variable sw, que es el ultimo renglon con datos, no se si fui claro, me confunden los simbolos $, no se mucho programar

  9. Hola tu método realmente me ha servido mucho, pero aún no logro crear la tabla, ya logré que excel seleccione el rango dinámico, pero cuando intento crear la tabla mediante:
    ActiveSheet.ListObjects.Add(xlScrRange, Range(«StartCell, sht.Cells(LRow, LColumn)»,False,xlYes).Name=»Base» Me arroja error. ¿Podrías ayudarme con ello?

    1. Hola Emmanuel.

      Si pasas entre comillas tus variables como en Range(«StartCell, sht.Cells(LRow, LColumn)») estas convirtiendolas a texto, por lo que pierden su valor.
      En su defecto seria:
      ActiveSheet.ListObjects.Add(xlSrcRange, Range(StartCell, sht.Cells(LRow, LColumn)),False,xlYes).Name=»Base»

      Saludos

  10. Hola, me pareció muy bien explicado. Excelente contenido, felicidades. Quisiera saber si con esta forma de crear rangos variables, puedo usarla para crear tablas dinámicas con rangos variables y cómo podría usarla. Mil gracias, saludos.

    1. Hola Karla.
      En efecto es posible con estos métodos. Un ejemplo seria:

      Sub tabla_dinamica()
      Dim rng As Range, startCell As Range
      Dim sht As Worksheet, pivotSht As Worksheet
      Dim lRow As Long, lColumn As Long
      Dim nombre as String

      Set sht = ThisWorkbook.Sheets(«Tabla_Ventas»)
      Set startCell = sht.Range(«A1»)
      lRow = sht.Cells(sht.Rows.Count, startCell.Column).End(xlUp).Row
      lColumn = sht.Cells(startCell.Row, sht.Columns.Count).End(xlToLeft).Column
      nombre = «tablaDinamicaNueva»

      Set rng = sht.Range(startCell, sht.Cells(lRow, lColumn))
      Set pivotSht = Sheets.Add

      ActiveWorkbook.PivotCaches.Create(SourceType:=xlDatabase, SourceData:= _
      rng, Version:=7).CreatePivotTable TableDestination:= _
      pivotSht.Range(«A3»), TableName:=nombre, DefaultVersion:=7

      End Sub

      Saludos.

  11. Hola, buen día.
    Acabo de llegar a la página y me parece muy interesante y muy bien explicado. Mi pregunta es si es posible hacer un rango dinámico con las filas de una tabla que cumplan cierta condición. Por ejemplo en una tabla de vendedores con su ubicación, salario, etc. y que haga un rango con todos los nombres que están en el norte. Cosa que si se elimina o se agrega un nuevo nombre, el rango se actualice solo. Finalmente ese rango lo usaría para una lista desplegable.
    He visto otros artículos que me han dado nuevas ideas para otras aplicaciones.
    Muchas gracias y saludos

    1. Hola Alex.
      Si es posible, podrías hacerlo dentro de la hoja con una macro de evento Changes, que evalue el rango segun los parametros de cambio.
      Adicional, si tienes Office 365 puedes hacer todo esto que comentas con la función FILTRAR. Agregas los parámetros y a la hora de crear la validación la usas con referencia de desbordamiento.

      Este artículo puede darte una idea.
      https://excelcute.com/arrays-dinamicos-excel-365/
      Saludos.

  12. Hola que tal, mi nombre es Ricardo, encontré estos ejemplos que se me hacen muy buenos, estoy trabajando en un pequeño proyecto, donde tengo rangos dinámicos y con celdas en blanco y filtros, por lo cual el ejemplo dos se me hice muy bueno.
    Encontré tus ejemplos buscando una respuesta, a ver si me ayudas, considerando que hay filtros para seleccionar por mes y la ultima celda fuera la «A20» y varias columnas, donde la fila 20 llevara subtotales y no todas las columnas.
    La pregunta es puedo y como seleccionar la celda «A20» como Rango y considerando que puede ser dinámica esa celda.
    Gracias, saludos

    1. Hola Ricardo.
      Que bueno saber que te sirvió.
      Para tomar como parámetro la última celda de una tabla filtrada podrías hacer uso del método dos y guardar la celda a la que llegas en una variable.

      Siguiendo el ejemplo de la entrada:

      Dim uCelda as Range
      Set uCelda = sh.Cells(sh.Rows.Count, 1).End(xlUp)

      Cualquier duda escríbeme con más detalles a svallejo@excelcute.com

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Scroll hacia arriba