Finding the last used row using VBA in Excel

last used row

Although the task to get the last row seems straight, there are quite a few considerations that pop up ones we start looking for a way to determine it. In this article an experimental approach is taken to determine the semantics and suitability of code fragments found on the web.

The test was done changing the active cell from A1, A2, ... F2 and each time rerun the procedure TestLastUsedRow below. The techniques tested are:

last row - in worksheet - usedrange - in column - xldown (allow blank cells?) - in region - currentregion - containing data / or also formatting? - number or range, entirerow or in - relative to starting range possible causes

What do we require to find?

Using

SpecialCells(xlCellTypeLastCell)

Using Worksheet.UsedRange

UsedRange returns a Range object representing the area of a worksheet that is being used in a broad sense including data, formatting and other uses. Therefore, if you are only interested in the last row containing data you can only use UsedRange as a boundary of the range in which the last row will be found.


Sub TestLastUsedRow()
Dim ws As Worksheet
Dim rng As Range: Set rng = ActiveCell
Set ws = rng.Worksheet
Dim rngSpecialCellsLastCell As Range: Set rngSpecialCellsLastCell = rng.SpecialCells(Type:=xlCellTypeLastCell)
Dim rngCurrentRegionLastRow As Range: Set rngCurrentRegionLastRow = rng.CurrentRegion
Dim rngUsedRangeLastRow As Range: Set rngUsedRangeLastRow = ws.UsedRange
Dim rngColumnEndXlDown As Range: Set rngColumnEndXlDown = rng.End(xlDown)
Dim rngFindPrevious As Range
Set rngFindPrevious = ws.Cells.Find(What:="*", After:=ws.Range("a1"), SearchOrder:=xlByRows, SearchDirection:=xlPrevious)
Debug.Print "rngSpecialCellsLastCell: " & rngSpecialCellsLastCell.Address & " - " & rngSpecialCellsLastCell.Row
Debug.Print "rngCurrentRegionLastRow: " & rngCurrentRegionLastRow.Address & " - " & rngCurrentRegionLastRow.Rows.Count
Debug.Print "rngUsedRangeLastRow:     " & rngUsedRangeLastRow.Address & " - " & rngUsedRangeLastRow.Rows.Count
Debug.Print "rngColumnEndXlDown:      " & rngColumnEndXlDown.Address & " - " & rngColumnEndXlDown.Row
Debug.Print "rngFindPrevious:         " & rngFindPrevious.Address & " - " & rngFindPrevious.Row
End Sub
A1
rngSpecialCellsLastCell: $F$8 - 8
rngCurrentRegionLastRow: $A$1:$D$3 - 3
rngUsedRangeLastRow:     $B$2:$F$9 - 8
rngColumnEndXlDown:      $A$1048576 - 1048576
rngFindPrevious:         $F$8 - 8
A2
rngSpecialCellsLastCell: $F$8 - 8
rngCurrentRegionLastRow: $A$2:$D$3 - 2
rngUsedRangeLastRow:     $B$2:$F$9 - 8
rngColumnEndXlDown:      $A$1048576 - 1048576
rngFindPrevious:         $F$8 - 8
B2
rngSpecialCellsLastCell: $F$8 - 8
rngCurrentRegionLastRow: $B$2:$D$3 - 2
rngUsedRangeLastRow:     $B$2:$F$9 - 8
rngColumnEndXlDown:      $B$1048576 - 1048576
rngFindPrevious:         $F$8 - 8
C2
rngSpecialCellsLastCell: $F$8 - 8
rngCurrentRegionLastRow: $B$2:$D$3 - 2
rngUsedRangeLastRow:     $B$2:$F$9 - 8
rngColumnEndXlDown:      $C$3 - 3
rngFindPrevious:         $F$8 - 8
D2
rngSpecialCellsLastCell: $F$8 - 8
rngCurrentRegionLastRow: $B$2:$D$3 - 2
rngUsedRangeLastRow:     $B$2:$F$9 - 8
rngColumnEndXlDown:      $D$3 - 3
rngFindPrevious:         $F$8 - 8
F2
rngSpecialCellsLastCell: $F$9 - 9
rngCurrentRegionLastRow: $F$2:$F$8 - 7
rngUsedRangeLastRow:     $B$2:$F$9 - 8
rngColumnEndXlDown:      $F$8 - 8
rngFindPrevious:         $F$8 - 8