Finding the Last Row with Data in VBA

Finding the Last Row with Data in VBA

When working with data in Excel using VBA, it’s a common task to determine the last row containing data in a worksheet. This is crucial for iterating through data, performing calculations, or adding new information. However, simply counting rows using Range.Rows.Count can lead to inaccurate results if the worksheet isn’t completely filled. This tutorial will guide you through various methods to reliably find the last row containing data in a VBA project.

The Problem with Simple Counting

A naive approach might involve using Range("A1", Range("A1").End(xlDown)).Rows.Count. While this works correctly if there are multiple rows with data, it fails when only the first cell (A1) contains data. In this scenario, the code incorrectly returns the maximum number of rows in Excel (1,048,576) instead of 1. This is because End(xlDown) continues to the very bottom of the sheet, even past any actual data.

Method 1: Working Upwards from the Bottom

A more robust approach is to start at the bottom of the column and work your way up until you find the last non-empty cell.

Sub FindLastRowBottomUp()
    Dim sh As Worksheet
    Set sh = ThisWorkbook.Sheets("Sheet1") ' Replace "Sheet1" with your sheet name

    Dim k As Long
    k = sh.Range("A1048576").End(xlUp).Row

    ' k now holds the last row number with data in column A
    Debug.Print k 'Output the result to the immediate window
End Sub

This code starts at cell A1048576 (the last row in Excel) and uses End(xlUp) to move upwards until it finds the first non-empty cell. The Row property then extracts the row number, giving you the last row containing data. This method is generally reliable and efficient.

Method 2: Utilizing the UsedRange Property

Excel’s UsedRange property returns a Range object that represents the cells containing data. However, be aware that the UsedRange can sometimes include cells that were used but are now empty, especially if formatting has been applied.

Sub FindLastRowUsedRange()
    Dim sh As Worksheet
    Dim rn As Range
    Set sh = ThisWorkbook.Sheets("Sheet1")

    Dim k As Long
    Set rn = sh.UsedRange
    k = rn.Rows.Count + rn.Row - 1

    ' k now holds the last row number with data
    Debug.Print k
End Sub

This code first obtains the UsedRange of the worksheet. Then, it calculates the last row number by adding the number of rows in the UsedRange to the starting row of the UsedRange and subtracting 1. The subtraction is necessary because Rows.Count includes the starting row.

Method 3: Finding Constant Cells

This approach leverages the SpecialCells method to identify cells containing constants (values, formulas that evaluate to values, etc.).

Sub FindLastRowConstantCells()
    Dim sh As Worksheet
    Set sh = ThisWorkbook.Sheets("Sheet1")

    Dim k As Long
    k = sh.Range("A:A").Cells.SpecialCells(xlCellTypeConstants).Count

    ' k now holds the last row number with data
    Debug.Print k
End Sub

This code finds all cells in column A that contain constants and counts them, effectively giving you the last row with data.

Method 4: Custom Function (Ron de Bruin’s Last Function)

A versatile solution is to use a custom function designed to find the last row and column. This function, originally created by Ron de Bruin, is a helpful addition to any VBA toolkit.

Function Last(choice As Long, rng As Range)
'Ron de Bruin, 5 May 2008
' 1 = last row
' 2 = last column
' 3 = last cell
    Dim lrw As Long
    Dim lcol As Long

    Select Case choice

    Case 1:
        On Error Resume Next
        Last = rng.Find(What:="*", _
                        After:=rng.Cells(1), _
                        Lookat:=xlPart, _
                        LookIn:=xlFormulas, _
                        SearchOrder:=xlByRows, _
                        SearchDirection:=xlPrevious, _
                        MatchCase:=False).Row
        On Error GoTo 0

    Case 2:
        On Error Resume Next
        Last = rng.Find(What:="*", _
                        After:=rng.Cells(1), _
                        Lookat:=xlPart, _
                        LookIn:=xlFormulas, _
                        SearchOrder:=xlByColumns, _
                        SearchDirection:=xlPrevious, _
                        MatchCase:=False).Column
        On Error GoTo 0

    Case 3:
        On Error Resume Next
        lrw = rng.Find(What:="*", _
                       After:=rng.Cells(1), _
                       Lookat:=xlPart, _
                       LookIn:=xlFormulas, _
                       SearchOrder:=xlByRows, _
                       SearchDirection:=xlPrevious, _
                       MatchCase:=False).Row
        On Error GoTo 0

        On Error Resume Next
        lcol = rng.Find(What:="*", _
                        After:=rng.Cells(1), _
                        Lookat:=xlPart, _
                        LookIn:=xlFormulas, _
                        SearchOrder:=xlByColumns, _
                        SearchDirection:=xlPrevious, _
                        MatchCase:=False).Column
        On Error GoTo 0

        On Error Resume Next
        Last = rng.Parent.Cells(lrw, lcol).Address(False, False)
        If Err.Number > 0 Then
            Last = rng.Cells(1).Address(False, False)
            Err.Clear
        End If
        On Error GoTo 0

    End Select
End Function

Sub TestLastFunction()
    Dim sh As Worksheet
    Set sh = ThisWorkbook.Sheets("Sheet1")
    Dim lastRow As Long
    lastRow = Last(1, sh.Range("A:A"))
    Debug.Print lastRow
End Sub

This function searches for the last cell containing any character (*) and returns the corresponding row or column number based on the choice argument (1 for last row, 2 for last column).

Choosing the Right Method

Each method has its strengths and weaknesses. The UsedRange method is convenient but can be inaccurate if the sheet has been heavily modified. The bottom-up approach and the custom function are generally more reliable. The constant cells method may not work if the cells contain formulas that evaluate to empty strings. Choose the method that best suits your specific needs and data structure.

Leave a Reply

Your email address will not be published. Required fields are marked *