查找仅包含最后一行的第一个单元格的范围?

时间:2018-12-09 14:19:31

标签: excel vba

我需要计算一个仅包含一个单元格的范围。该单元格来自最后一行和第一列。如果工作表为空,则范围为A1:A1

我知道有很多方法可以计算最后一行,但是我正在寻找一种优雅的方法来获取最后一行的第一行。也许有些例子可以更好地解释。

示例1

 A B C D
1
2  X
3      X
4    X

结果#1

Range = A4:A4

示例2

 A B C D
1

结果#2

Range = A1:A1

该怎么做?

4 个答案:

答案 0 :(得分:0)

如果我正确理解,则希望找到某个范围(或一堆列)中的最后一行。

一种实现此目的的方法可能是循环遍历该范围内的每一列,找到最后一个单元格(在该特定列中)的哪一行,并检查它是否超过了循环中迄今为止最大的最后一行。

在下面的代码中,如果将"Sheet1"更改为工作表调用的名称,并将范围从"A4:Z5"更改为"A:Z""A1:D4"(或其他任何名称) (以您的情况为准),然后应显示您要查找的单元格的地址。

Option Explicit

Private Sub ShowLastCell()
    ' Change this to what your sheet is called.
    With ThisWorkbook.Worksheets("Sheet1")

        ' Change this to the range you need to check.
        With .Range("A4:Z5")
            Dim firstColumnToCheck As Long
            firstColumnToCheck = .Columns(1).Column

            Dim lastColumnToCheck As Long
            lastColumnToCheck = .Columns(.Columns.Count).Column
        End With

        Dim maxLastRow As Long
        Dim columnIndex As Long

        For columnIndex = firstColumnToCheck To lastColumnToCheck
            maxLastRow = Application.Max(maxLastRow, .Cells(.Rows.Count, columnIndex).End(xlUp).Row)
        Next columnIndex

        MsgBox ("I think the cell you want is " & .Cells(maxLastRow, "A").Address & ":" & .Cells(maxLastRow, "A").Address)

    End With
End Sub

答案 1 :(得分:0)

GetFirstCellInLastLine 将返回所引用工作表最后一行中的第一个单元格作为Range对象。然后,您可以使用它来做您想做的事情。例如,打印到活动工作表的“立即窗口”:

Debug.Print GetFirstCellInLastLine(ActiveSheet).Address

如果工作表为空白,则设置为返回注意,但是您可以根据需要进行修改:

'''
''' Returns the first used cell in the last line of the worksheet.
''' Returns "Nothing" if the worksheet is blank.
'''
Public Function GetFirstCellInLastLine(ws As Excel.Worksheet) As Excel.Range

Dim rng As Excel.Range

    Set rng = ws.UsedRange.Cells(ws.UsedRange.Rows.Count, 1)

    If ((ws.UsedRange.Columns.Count > 1) And ws.Range(rng, rng.End(xlToRight)).Columns.Count <= ws.UsedRange.Columns.Count) Then
        Set rng = ws.Range(rng, rng.End(xlToRight))
        If VBA.IsEmpty(rng.Cells(1, 1)) Then
            Set rng = rng.Cells(1, rng.Columns.Count)
        Else
            Set rng = rng.Cells(1, 1)
        End If
    ElseIf (ws.UsedRange.Columns.Count = 1) And VBA.IsEmpty(rng.Cells(1, 1)) Then
        Set rng = Nothing
    End If

    Set GetFirstCellInLastLine = rng

End Function

答案 2 :(得分:0)

上次使用的行和指定列的交集专长。 UsedRange

一种优雅的方法是使用 UsedRange 属性。

高级版本

'*******************************************************************************
' Purpose:    Using the UsedRange Property, creates a reference to the cell    *
'             range at the intersection of the last used row and a specified   *
'             column in a worksheet and prints its address and the address     *
'             of the UsedRange to the Immediate Window.                        *
'*******************************************************************************
Sub LastUR_Column_UsedRange()

  Const cVntCol As Variant = "A"  ' Column
  Dim objRngT As Range            ' Target Range

  With ThisWorkbook.Worksheets("Sheet1")
    If .Cells(.UsedRange.Rows.Count + .UsedRange.Row - 1, cVntCol).Row = 1 _
        And .Cells(1, Columns.Count).End(xlToLeft).Column = 1 _
        And IsEmpty(.Cells(1, 1)) Then
      Debug.Print "objRngT = Nothing (Empty Worksheet)"
     Else
      Set objRngT = .Cells(.UsedRange.Rows.Count + .UsedRange.Row - 1, cVntCol)
      Debug.Print "objRngT = " & objRngT.Address & " calculated from the " _
          & "used range (" & .UsedRange.Address & ")."
      Set objRngT = Nothing
    End If
  End With

End Sub
'*******************************************************************************

课程版本

'*******************************************************************************
' Purpose:    Using the UsedRange Property, creates a reference to the cell    *
'             range at the intersection of the last used row and a specified   *
'             column in a worksheet and prints subresults and  its address     *
'             to the Immediate Window.                                         *
'*******************************************************************************
Sub LastUR_Column_UsedRange_Lesson()

  ' When you declare the column as variant you can use
  ' column letter or number e.g. "A" or 1, "D" or 4 ...
  Const cVntCol As Variant = "A"    ' Column

  Dim objRngT As Range              ' Target Range

  Dim lngLast As Long               ' Last Row
  Dim lngRows As Long               ' Number of Rows
  Dim lngFirst As Long              ' First Row

  With ThisWorkbook.Worksheets("Sheet1")

    ' Finding first row and number of rows is easy.
    lngFirst = .UsedRange.Row
        Debug.Print "lngFirst  = " & lngFirst
    lngRows = .UsedRange.Rows.Count
        Debug.Print "lngRows   = " & lngRows

    ' Note1: Only when there is data in the first row, the number of rows
    '        is equal to the last row.

    ' Therefore we have to calculate the last row.
    lngLast = lngRows + lngFirst - 1
        Debug.Print "lngLast   = " & lngLast

    ' Now imagine you have the first data in row 2, and you have 3 rows
    ' which would mean the last data is in row 4 (rows 2, 3, 4). So when you add
    ' 2 + 3 = 5, you have to subtract 1 row, because you counted row 2 twice.

    ' Note2: If there is data in the first row then lngFirst = 1.
    '        So the formula will calculate:
    '          lnglast = lngRows + 1 - 1
    '          lngLast = lngRows + 0
    '         which proves the statement in Note1.

    ' The previous three lines could have been written in one line:
    lngLast = .UsedRange.Rows.Count + .UsedRange.Row - 1
        Debug.Print "lngLast   = " & lngLast & " (One Row Version)"

    ' Now we have all the ingredients for the Target Range.
    Set objRngT = .Cells(lngLast, cVntCol)
        Debug.Print "objRngT   = " & objRngT.Address _
            & " (Before Check if Empty)"

    ' And again all this could have been written in one line:
    Set objRngT = .Cells(.UsedRange.Rows.Count + .UsedRange.Row - 1, cVntCol)
        Debug.Print "objRngT   = " & objRngT.Address & " (One Row Version)" _
             & " (Before Check if Empty)"
    ' then you wouldn't need variables lngLast, lngFirst and lngRows. On the
    ' other hand you wouldn't have learned how this big formula was created.

    ' Now the problem is that if the worksheet is empty, UsedRange will show
    ' the cell in the first row as the used range. So we have to address this
    ' issue by checking if all of the following three conditions are true.
    ' - Check if the resulting cell range is in the first row (1).
    ' - Check if from the end of the first row to the beginning the result
    '   is the first cell (1) (all other cells are empty).
    ' - Check if the cell ("A1") is empty.
    If objRngT.Row = 1 And _
        .Cells(1, Columns.Count).End(xlToLeft).Column = 1 And _
        IsEmpty(.Cells(1, 1)) Then
      Debug.Print "objRngT   = Nothing (Empty Worksheet)"
     Else
      Debug.Print "objRngT   = " & objRngT.Address
    End If
    ' Although this is a working code, we can conclude that we should have done
    ' this checking at the beginning which will be done in the advanced version.

  End With

  Set objRngT = Nothing

End Sub
'*******************************************************************************

答案 3 :(得分:0)

最后使用的行和指定列的交集专长。

查找方法

我将其称为最安全且最优雅的方式:使用 Find 方法。

'*******************************************************************************
' Purpose:    Using the Find method, creates a reference to the cell range at  *
'             the intersection of the last used row and a specified column     *
'             in a worksheet and prints its address to the Immediate window.   *
'*******************************************************************************
Sub LastUR_Column_Find()

  Const cVntCol As Variant = "A"  ' Column Letter or Number ("A" or 1)
  Dim objRngT As Range            ' Target Range

  With ThisWorkbook.Worksheets("Sheet1")
    If Not .Cells.Find("*", .Cells(.Rows.Count, .Columns.Count), -4123, , 1) _
        Is Nothing Then
      Set objRngT = .Cells(.Cells.Find("*", , , , , 2).Row, cVntCol)
      Debug.Print "objRngT = " & objRngT.Address
      Set objRngT = Nothing
     Else
      Debug.Print "objRngT = Nothing (Empty Worksheet)"
    End If
  End With

End Sub
'*******************************************************************************
' Remarks:    If you carefully study the "Find method as it applies to         *
'             the Range object." from "Visual Basic Help", you will realize    *
'             why exactly those four arguments and their parameters in         *
'             the If statement must be included and why three of them can      *
'             be omitted, but a new one has to be added in the Else clause.    *
'*******************************************************************************