3
votes

I'm new here and I'm looking to use Excel VBA to return the last used cell in a worksheet.

I'vv looked at Error in finding last used cell in Excel with VBA) but that didn't answer the two problems I have:

  1. The .Cells.Find(...).Row method takes WAY too long in my code.

  2. My meaning of "last used cell" might be odd...the cell can be blank. I want to take the column that has the last used cell and pair it with the row that has the last used cell.

To explain: Assume a sheet is empty except for data in A1:C3, D2 and B4. (Exhibit 1)

The last cell I'm interested in is D4because I want the last cell in the sheet that includes all data in the sheet.

enter image description here

Now that I've explained what I'm looking for, can anyone provide suggestions as to either

  • how to make cells.find run faster or
  • another credible method to find the "last cell" in a worksheet?

Thank you!

4
So find the last row and the last column, then combine them into a range...Comintern
Thanks Comintern. That's what I'm currently doing with ".Cells.Find()" but it's taking way too long. Thoughts?Tuckertubaman
Not without seeing the code.Comintern
I think you're going to need to flesh out this question. Specifically, does 'last cell' include or exclude hidden cells, formatted cells (even if cell is blank), cells with "" in them (which, for example, Find("*") wouldn't catch), etc. Also, as @Comintern suggests, showing the code you have tried so far inclines people to help you more.Ambie

4 Answers

6
votes

Did you try this?

Dim r As Range
Set r = Sheet1.UsedRange.SpecialCells(xlCellTypeLastCell)
Debug.Print r.Address

Output for your example:

$D$4

The UsedRange is known to not always match the actually used data range. Some workaround would be to use CurrentRegion:

Dim r As Range
With Sheet1.Range("A1").CurrentRegion
    Set r = Sheet1.Cells(.Rows.count, .Columns.count)
End With
Debug.Print r.Address

also if the data does not start at A1, maybe this:

With Sheet1.Cells.Find("*").CurrentRegion
4
votes

Use Find both by row and column to identify this cell.

  Sub GetLastCellRange()
        Dim rng1 As Range
        Dim rng2 As Range
        Dim rng3 As Range
        Set rng1 = Cells.Find("*", [a1], xlFormulas, , xlByRows, xlPrevious)
        Set rng2 = Cells.Find("*", [a1], xlFormulas, , xlByColumns, xlPrevious)
        If Not rng1 Is Nothing Then
            Set rng3 = Range([a1], Cells(rng1.Row, rng2.Column))
            MsgBox "Range is " & rng3.Address(0, 0)
            'if you need to actual select the range (which is rare in VBA)
            Application.Goto rng3 
        Else
            MsgBox "sheet is blank", vbCritical
        End If
    End Sub
0
votes
    'function that return a range object
    Function fRNGlastCellInWorksheet(owsActive As Worksheet) As Range
    Dim dblValues As Double
    Dim dblRow As Double
    Dim dblColumn As Double
    Dim rngActive As Range
    Dim dblValuesCount As Double
    
        'total number of cells found containing a value in the whole worksheet
        dblValues = Application.WorksheetFunction.CountA(owsActive.Cells)
        dblValuesCount = 0
        
        'loop through all columns in the worksheet until the condition is met and store the column number is a variable
        For Each rngActive In owsActive.Columns
            
           'add the total number of cells found containing a value in a specific column to the total number of cells found containing a value of all previous columns
            dblValuesCount = dblValuesCount + Application.WorksheetFunction.CountA(rngActive.Cells)

            'if the total number of cells found containing a value in the whole worksheet is equal to the total number of cells found containing a value in all previous columns, exit the loop
            If dblValuesCount = dblValues Then
                dblColumn = rngActive.Column
                Exit For
            End If
        Next rngActive
        
        dblValuesCount = 0

        'loop through all rows in the worksheet until the condition is met and store the row number in a variable
        For Each rngActive In owsActive.Rows
            
            'add the total number of cells found containing a value in a specific row to the total number of cells found containing a value of all previous rows
            dblValuesCount = dblValuesCount + Application.WorksheetFunction.CountA(rngActive.Cells)

             'if the total number of cells found containing a value in the whole worksheet is equal to the total number of cells found containing a value in all previous rows, exit the loop            
            If dblValuesCount = dblValues Then
                dblRow = rngActive.Row
                Exit For
            End If
        Next rngActive
        

        'use the variable containing the column number and the variable containing the row number to define the range cell
        Set fRNGlastCellInWorksheet = owsActive.Cells(dblRow, dblColumn)
    
    
    End Function
-1
votes

Although the answers are very valid, I'd be careful using SpecialCells, CurrentRegion and all those.

Although they work most of the time, they are not 100% reliable in my experience.

For example, CurrentRegion will not pick up all data if the data happens to have an empty column or row etc.

The best Approach, in my opinion is to always use headers with your data. You can then enumerate all headers and find the last used row in that column. You can then determine the greatest row used and now define your data range.

Btw, if you select the last cell in a specified column then use the Range.End(xlUp) you can quickly determine the last used row for that column without Looping.