Cuando quiero encontrar el último valor de celda utilizado, uso:
Dim LastRow As Long
LastRow = Range("E4:E48").End(xlDown).Row
Debug.Print LastRow
Estoy obteniendo el resultado incorrecto cuando pongo un solo elemento en una celda. Pero cuando pongo más de un valor en la celda, la salida es correcta. ¿Cuál es la razón detrás de esto?
excel
vba
excel-formula
James
fuente
fuente
Respuestas:
NOTA : Tengo la intención de hacer de esto una "publicación única" en la que pueda usar la
Correct
forma de encontrar la última fila. Esto también cubrirá las mejores prácticas a seguir al encontrar la última fila. Y, por lo tanto, seguiré actualizándolo cada vez que encuentre un nuevo escenario / información.Formas poco confiables de encontrar la última fila
Algunas de las formas más comunes de encontrar la última fila son muy poco confiables y, por lo tanto, nunca deben usarse.
UsedRange
debe NUNCA ser utilizado para encontrar la última celda que tiene datos. Es muy poco confiable. Prueba este experimento.Escribe algo en la celda
A5
. Ahora, cuando calcules la última fila con cualquiera de los métodos que figuran a continuación, te dará 5. Ahora colorea la celda deA10
rojo. Si ahora usa cualquiera de los siguientes códigos, todavía obtendrá 5. Si usa,Usedrange.Rows.Count
¿qué obtiene? No serán las 5.Aquí hay un escenario para mostrar cómo
UsedRange
funciona.xlDown
Es igualmente poco confiable.Considera este código
¿Qué pasaría si solo hubiera una celda (
A1
) que tuviera datos? ¡Terminarás llegando a la última fila de la hoja de trabajo! Es como seleccionar la celdaA1
y luego presionar la Endtecla y luego presionar la Down Arrowtecla. Esto también le dará resultados poco confiables si hay celdas en blanco en un rango.CountA
tampoco es confiable porque le dará un resultado incorrecto si hay celdas en blanco en el medio.Y por lo tanto, uno debe evitar el uso de
UsedRange
,xlDown
yCountA
encontrar la última celda.Encuentra la última fila en una columna
Para encontrar la última fila en la columna E, use esto
Si notas que tenemos un
.
antesRows.Count
. A menudo elegimos ignorar eso. Vea ESTA pregunta sobre el posible error que puede obtener. Siempre aconsejo usar.
antesRows.Count
yColumns.Count
. Esa pregunta es un escenario clásico donde el código fallará porque losRows.Count
retornos65536
para Excel 2003 y anteriores y1048576
para Excel 2007 y posteriores. Del mismo modoColumns.Count
vuelve256
y16384
, respectivamente.El hecho anterior de que Excel 2007+ tiene
1048576
filas también enfatiza el hecho de que siempre debemos declarar la variable que contendrá el valor de la fila, ya que enLong
lugar deInteger
eso obtendrá unOverflow
error.Tenga en cuenta que este enfoque omitirá las filas ocultas. Mirando hacia atrás en mi captura de pantalla anterior para la columna A , si la fila 8 estuviera oculta, este enfoque volvería en
5
lugar de hacerlo8
.Encuentra la última fila en una hoja
Para encontrar la
Effective
última fila en la hoja, use esto. Observe el uso deApplication.WorksheetFunction.CountA(.Cells)
. Esto es necesario porque si no hay celdas con datos en la hoja de trabajo,.Find
le daráRun Time Error 91: Object Variable or With block variable not set
Buscar la última fila en una tabla (ListObject)
Se aplican los mismos principios, por ejemplo, para obtener la última fila en la tercera columna de una tabla:
fuente
Usedrange.Rows.Count
¿qué obtiene? No será 5. El rango utilizado no es muy confiable para encontrar la última fila.remembers
la última configuración. Incluso cuando realiza manualmente unFind
, recuerda la última configuración, que de hecho es una bendición si uno conoce este "hecho"UsedRange
( es muy poco confiable encontrar la última celda que tiene datos ) es engañosa.UsedRange
simplemente no está destinado para ese propósito, aunque en algunos casos puede dar el resultado correcto. Creo que el experimento propuesto se suma a la confusión. El resultado obtenido conUsedRange
($ A $ 1: $ A $ 8) no depende de ingresar primero los datos y eliminarlos. La figura de la derecha seguirá siendo la misma incluso sin haber ingresado datos y eliminado. Por favor mira mi respuesta.Nota: esta respuesta fue motivada por este comentario . El propósito de
UsedRange
es diferente de lo que se menciona en la respuesta anterior.En cuanto a la forma correcta de encontrar la última celda utilizada, primero hay que decidir qué se considera utilizado y luego seleccionar un método adecuado . Concibo al menos tres significados:
Usado = no en blanco, es decir, que tiene datos .
Used = "... en uso, es decir, la sección que contiene datos o formato ". Según la documentación oficial , este es el criterio utilizado por Excel al momento de guardar. Consulte también esta documentación oficial . Si uno no es consciente de esto, el criterio puede producir resultados inesperados, pero también puede explotarse intencionalmente (con menos frecuencia, seguramente), por ejemplo, para resaltar o imprimir regiones específicas, que eventualmente pueden no tener datos. Y, por supuesto, es deseable como criterio para el rango a utilizar al guardar un libro de trabajo, para no perder parte del trabajo de uno.
Usado = "... en uso, es decir, la sección que contiene datos o formato " o formato condicional. Igual que 2., pero también incluye celdas que son el objetivo de cualquier regla de Formato condicional.
Cómo encontrar la última celda utilizada depende de lo que desee (su criterio) .
Para el criterio 1, sugiero leer esta respuesta . Tenga en cuenta que
UsedRange
se cita como poco confiable. Creo que eso es engañoso (es decir, "injusto"UsedRange
), yaUsedRange
que simplemente no está destinado a informar la última celda que contiene datos. Por lo tanto, no debe usarse en este caso, como se indica en esa respuesta. Ver también este comentario .Para el criterio 2,
UsedRange
es la opción más confiable , en comparación con otras opciones también diseñadas para este uso. Incluso hace innecesario guardar un libro de trabajo para asegurarse de que se actualice la última celda. Ctrl+ Endirá a una celda incorrecta antes de guardar ("La última celda no se restablece hasta que guarde la hoja de trabajo", de http://msdn.microsoft.com/en-us/library/aa139976%28v=office.10% 29.aspx . Es una referencia antigua, pero a este respecto es válida).Para el criterio 3, no conozco ningún método incorporado . El criterio 2 no tiene en cuenta el formato condicional. Uno puede tener celdas formateadas, basadas en fórmulas, que no son detectadas por
UsedRange
o Ctrl+ End. En la figura, la última celda es B3, ya que el formato se le aplicó explícitamente. Las celdas B6: D7 tienen un formato derivado de una regla de Formato condicional, y esto ni siquiera lo detectaUsedRange
. Tener en cuenta esto requeriría cierta programación de VBA.En cuanto a su pregunta específica : ¿Cuál es la razón detrás de esto?
Su código usa la primera celda en su rango E4: E48 como un trampolín, para saltar con
End(xlDown)
.La salida "errónea" se obtendrá si no hay celdas no vacías en su rango que no sean las primeras. Luego, estás saltando en la oscuridad , es decir, hacia abajo en la hoja de trabajo (¡debes notar la diferencia entre una cadena en blanco y vacía !).
Tenga en cuenta que:
Si su rango contiene celdas no en blanco no contiguas, también dará un resultado incorrecto.
Si solo hay una celda no en blanco, pero no es la primera, su código aún le dará el resultado correcto.
fuente
Creé esta función integral para determinar la última fila, columna y celda, ya sea para datos, celdas formateadas (agrupadas / comentadas / ocultas) o formato condicional .
Los resultados se ven así:
Para resultados más detallados, algunas líneas en el código pueden ser descomentadas:
Existe una limitación: si hay tablas en la hoja, los resultados pueden volverse poco confiables, por lo que decidí evitar ejecutar el código en este caso:
fuente
Una nota importante a tener en cuenta al usar la solución ...
... es asegurarse de que su
LastRow
variable sea deLong
tipo:De lo contrario, terminará recibiendo errores de DESBORDAMIENTO en ciertas situaciones en los libros de trabajo .XLSX
Esta es mi función encapsulada que uso en varios usos de código.
fuente
Agregaría a la respuesta dada por Siddarth Rout para decir que la llamada CountA se puede omitir haciendo que Find devuelva un objeto Range, en lugar de un número de fila, y luego pruebe el objeto Range devuelto para ver si es Nothing (hoja de trabajo en blanco) .
Además, me gustaría que mi versión de cualquier procedimiento de LastRow devuelva un cero para una hoja de trabajo en blanco, entonces puedo saber que está en blanco.
fuente
Me pregunto si nadie ha mencionado esto, pero la forma más fácil de obtener la última celda utilizada es:
Esto esencialmente devuelve la misma celda que obtiene por Ctrl+ Enddespués de seleccionar Celda
A1
.Una advertencia: Excel realiza un seguimiento de la celda más inferior derecha que se haya utilizado en una hoja de trabajo. Entonces, si por ejemplo ingresas algo en B3 y algo más en H8 y luego eliminas el contenido de H8 , presionar Ctrl+ Endaún te llevará a la celda H8 . La función anterior tendrá el mismo comportamiento.
fuente
Last Cell
en Excel a veces se refiere a una celda vacía (desdeUsed Range
) que es diferente deLast Used Cell
;).Cells(1,1).Select()
no es válido es que tal vezActiveSheet.Cells(1,1).Select
; También en VBA no se recomienda su usoSelect
;).Set
.Dado que la pregunta original es sobre problemas para encontrar la última celda, en esta respuesta enumeraré las diversas formas en que puede obtener resultados inesperados ; vea mi respuesta a "¿Cómo puedo encontrar la última fila que contiene datos en la hoja de Excel con una macro?" por mi opinión sobre resolver esto.
Comenzaré ampliando la respuesta de sancho.s y el comentario de GlennFromIowa , agregando aún más detalles:
Otras cosas que puede considerar:
Con eso en mente, veamos cómo las formas comunes de obtener la "última celda" pueden producir resultados inesperados:
.End(xlDown)
código de la pregunta se romperá más fácilmente (por ejemplo, con una sola celda no vacía o cuando hay celdas en blanco en el medio ) por las razones explicadas en la respuesta de Siddharth Rout aquí (buscar "xlDown es igualmente poco confiable". ) 👎Count
ing (CountA
oCells*.Count
) o.CurrentRegion
también se romperá en presencia de celdas o filas en blanco 👎.End(xlUp)
buscar hacia atrás desde el final de una columna, al igual que CTRL + ARRIBA, buscará datos (las fórmulas que producen un valor en blanco se consideran "datos") en filas visibles (por lo que usarlo con el autofiltro habilitado puede producir resultados incorrectos ⚠️ )Debe evitar las trampas estándar (para obtener más detalles, volveré a consultar la respuesta de Siddharth Rout aquí, busque la sección "Buscar la última fila en una columna" ), como codificar la última fila (
Range("A65536").End(xlUp)
) en lugar de dependersht.Rows.Count
..SpecialCells(xlLastCell)
es equivalente a CTRL + FIN, devolviendo la celda más inferior y más a la derecha del "rango usado", por lo que todas las advertencias que se aplican a confiar en el "rango usado", también se aplican a este método. Además, el "rango utilizado" solo se restablece al guardar el libro de trabajo y al accederworksheet.UsedRange
, por lo quexlLastCell
puede producir resultados obsoletos⚠️ con modificaciones no guardadas (por ejemplo, después de que se eliminan algunas filas). Vea la respuesta cercana de dotNET .sht.UsedRange
(descrito en detalle en la respuesta de sancho.s aquí) considera tanto los datos como el formato (aunque no el formato condicional) y restablece el "rango utilizado" de la hoja de trabajo , que puede o no ser lo que desea.Tenga en cuenta que un error común ️ es usar
.UsedRange.Rows.Count
⚠️, que devuelve el número de filas en el rango utilizado, no el número de la última fila (serán diferentes si las primeras filas están en blanco), para más detalles vea la respuesta de Newguy a ¿Cómo puedo encontrar? última fila que contiene datos en la hoja de Excel con una macro?.Find
le permite encontrar la última fila con cualquier dato (incluidas las fórmulas) o un valor que no esté en blanco en cualquier columna . Puede elegir si le interesan las fórmulas o los valores, pero el problema es que restablece los valores predeterminados en el cuadro de diálogo Buscar de Excel ️️⚠️, lo que puede ser muy confuso para sus usuarios. También debe usarse con cuidado, vea la respuesta de Siddharth Rout aquí (sección "Buscar la última fila en una hoja" )Cells
en un bucle generalmente son más lentas que volver a usar una función de Excel (aunque todavía puede ser eficaz), pero le permiten especificar exactamente lo que desea encontrar. Vea mi solución basada enUsedRange
matrices VBA para encontrar la última celda con datos en la columna dada: maneja filas ocultas, filtros, espacios en blanco, no modifica los valores predeterminados de búsqueda y es bastante eficiente.Sea cual sea la solución que elija, tenga cuidado
Long
lugar deInteger
almacenar los números de fila (para evitar obtenerOverflow
más de 65k filas) yDim ws As Worksheet ... ws.Range(...)
lugar deRange(...)
).Value
(que es aVariant
) evite conversiones implícitas,.Value <> ""
ya que fallarán si la celda contiene un valor de error.fuente
Sin embargo, esta pregunta busca encontrar la última fila usando VBA, creo que sería bueno incluir una fórmula de matriz para la función de la hoja de trabajo, ya que esta se visita con frecuencia:
Debe ingresar la fórmula sin corchetes y luego presionar Shift+ Ctrl+Enter para convertirla en una fórmula de matriz.
Esto le dará la dirección de la última celda utilizada en la columna D.
fuente
Aquí, A65536está la última celda en la Columna A, este código fue probado en Excel 2003.
fuente
Estaba buscando una manera de imitar el CTRL+ Shift+ End, por lo que la solución dotNET es excelente, excepto que con mi Excel 2010 necesito agregar un
set
si quiero evitar un error:y cómo comprobar esto por ti mismo:
fuente
Aquí están mis dos centavos.
En mi humilde opinión, el riesgo de una fila oculta con la exclusión de datos es demasiado importante como para dejarlo
xlUp
como una respuesta integral . Estoy de acuerdo en que es simple y funcionará la mayor parte del tiempo, pero presenta el riesgo de subestimar la última fila, sin previo aviso. Esto podría producir CATASTROPHIC resultados en algún momento para alguien que saltó a Stack Overlow y estaba buscando "una forma segura" de capturar este valor.El
Find
método es perfecto y lo aprobaría como una respuesta única . Sin embargo, el inconveniente de cambiar laFind
configuración puede ser molesto, especialmente si es parte de un UDF.Las otras respuestas publicadas están bien, sin embargo, la complejidad se vuelve un poco excesiva. Por lo tanto, aquí está mi intento de encontrar un equilibrio de confiabilidad, complejidad mínima y no usar
Find
.Por qué esto es bueno:
Find
configuraciónPor qué esto es malo:
Sin embargo, creo que una
find
solución integral que tiene el inconveniente de estropear la configuración o funcionar más lentamente es una mejor solución general. Un usuario puede luego modificar su configuración para intentar mejorar, sabiendo lo que está sucediendo con su código. El usoxLUp
no advertirá sobre los riesgos potenciales y podrían continuar por quién sabe cuánto tiempo sin saber que su código no funcionaba correctamente.fuente
Durante los últimos 3 años, estas son las funciones que estoy usando para encontrar la última fila y la última columna por columna definida (para la fila) y fila (para la columna):
Última columna:
Última fila:
Para el caso del OP, esta es la forma de obtener la última fila en la columna
E
:Debug.Print lastRow(columnToCheck:=Range("E4:E48").Column)
Última fila, contando filas vacías con datos:
Aquí podemos usar las conocidas fórmulas de Excel , que nos dan la última fila de una hoja de cálculo en Excel, sin involucrar a VBA:
=IFERROR(LOOKUP(2,1/(NOT(ISBLANK(A:A))),ROW(A:A)),0)
Para poner esto en VBA y no escribir nada en Excel, usando los parámetros para las últimas funciones, algo como esto podría estar en mente:
fuente
EVAL()
la famosa fórmula de Excel. Aunque la gente puede pensar queEval()
es malo y esta es otra historia interesante sobre la que escribir ...fuente