【问题标题】:Finding the last row of an Excel spreadsheet when the last row is hidden隐藏最后一行时查找 Excel 电子表格的最后一行
【发布时间】:2012-12-21 10:40:07
【问题描述】:

我正在尝试在 A 列中查找包含具有以下代码的值的最后一行:

LastRow = DataWorksheet.Range("A:A").Find(What:="*", SearchOrder:=xlRows, SearchDirection:=xlPrevious, LookIn:=xlValues).Row

这适用于大多数情况,除了最后几行被过滤掉。例如,假设我们有 30 行数据。如果 1-10 行可见,11-20 行被过滤掉,21-30 行可见,则成功找到最后一行:返回 30。当一切可见且过滤掉 21-30 行时,LastRow 返回 1。

请注意,如果我手动隐藏而不是过滤掉第 21-30 行,它会告诉我最后一行是 20。

什么给了?如果最后一行被过滤,我如何让它确定最后一行是什么?

编辑: 现在似乎 LastRow 正在挑选最后一个 unfiltered 行,这与其之前的行为明显不同。一旦我能够更好地隔离我遇到的错误/不一致,我将更新这篇文章。

【问题讨论】:

  • ...我真的很困惑-您的代码给了我最后未过滤的行,而@MattCrum's 给了最后一行数据...似乎您可以得到...
  • 试试这个stackoverflow.com/questions/11169445/… 使用.Find 方法
  • Sid,如果最后一行被隐藏,将找不到正确的最后一行。

标签: excel excel-2007 vba


【解决方案1】:

这些应该忽略过滤/可见性并为您提供最后使用的行号:

DataWorksheet.UsedRange.Rows.Count

-或-

DataWorksheet.Range("A1").SpecialCells(xlCellTypeLastCell).Row

在 A 列中都找不到最后使用的单元格,但是……这是您需要的吗?

【讨论】:

  • 是的。我尝试了这两种方法,但我真正感兴趣的是最后一个有值的单元格。
  • 这些答案没有给出最后一个单元格的值,只是UsedRange。 PS UsedRange 确实必须从单元格 A1 开始,如果工作表具有随时间更新的大型数据集,则通常是整个工作表。
【解决方案2】:

这个怎么样(作为一种解决 XL 限制的工作)。循环有点长/笨重,但至少循环从第一个可见的最后一个单元格开始。

LastRow = DataWorksheet.Range("A:A").Find(What:="*", SearchOrder:=xlRows, SearchDirection:=xlPrevious, LookIn:=xlValues).Row


If LastRow <> DataWorksheet.UsedRange.Rows.Count 'assumes data starts in A1, if not adjust acoordingly

'now check if there is anything below

    Dim rngSearch as Range
    rngSearch = DataWorksheet.Range("A" & LastRow & ":A" & DataWorksheet.UsedRange.Rows.Count)

    Dim lngRows as Long, lngCnt as Long
    lngRows = rngSearch.Rows.Count

    For lngCnt = lngRows to 1 Step -1

        If DataWorksheet.Range("A" & lngCnt) = vbNullString And DataWorksheet.Range("A" & lngCnt -1) <> vbNullString Then

            LastRow = DataWorksheet.Range("A" & lngCnt-1).Row
        End If

    Next

End If

【讨论】:

    【解决方案3】:

    这适用于具有隐藏行和自动过滤器的工作表。如果最后一个具有值的单元格下方的单元格已被格式化(这将导致 usedrange 大于您要查找的行),它也不会为您提供不正确的行。

    Sub FindLastRowWithValue()
        Dim ws As Worksheet
        Dim temp As Worksheet
        Dim lastrow As Long
    
        ' copy the sheet that may have hidden rows
        Set ws = Sheets("Sheet1")
        ws.Copy Before:=Sheets(1)
        Set temp = ActiveSheet
    
        ' turn off autofiltering if need be
        If temp.AutoFilterMode Then temp.AutoFilterMode = False
    
        ' unhide all rows
        temp.Columns("A:A").EntireRow.Hidden = False
    
        ' get the last row with a value now that all rows are unhidden
        lastrow = temp.Range("A" & temp.Rows.Count).End(xlUp).Row
    
        ' delete the temporary sheet
        Application.DisplayAlerts = False
        temp.Delete
        Application.DisplayAlerts = True
    
        MsgBox lastrow
    End Sub
    

    【讨论】:

    • @slothario:你试过这个吗?
    • 感谢您回复我!我目前急于赶上工作的最后期限,所以我现在不得不把这个问题放在一边,然后再回来,但我会确保在能够深入了解它时更新这个线程。
    【解决方案4】:

    在经历了很多挫折之后,“vba 内置”方法似乎总是存在问题。例如,列“A”和“WS”是工作表对象:

    • « Ws.Cells(WS.Rows.Count,1).End(xlUp) » 因隐藏行而失败
    • « WS.Range("A1").Find(...) » 在组中隐藏行时失败(可能还有其他情况)
    • « UsedRange » 和 « .SpecialCells(xlLastCell) » 返回的结果可能高于预期

    我的解决方案是使用带有“WorkSheet.Evaluate”的 Excel 公式。

    检查非空值(即不考虑结果为空的公式):

    Function FindLastRow(R as Range) As Long
        Const NotFoundResult = 1 ' If all cells have an empty value, this value is returned
        FindLastRow = R.Worksheet.Evaluate("IFERROR(LARGE(ROW('" & R.Worksheet.Name & "'!" & R.Address & ")*--('" & R.Worksheet.Name & "'!" & R.Address & " <> """"),1)," & NotFoundResult & ")")
    End Function
    

    使用公式或值检查最后一个单元格(即使结果为空):

    Function FindLastRow(R as Range) As Long
        Const NotFoundResult = 1 ' If all cells are empty (no value, no formula), this value is returned
        FindLastRow = R.Worksheet.Evaluate("IFERROR(LARGE(ROW('" & R.Worksheet.name & "'!" & R.Address & ")*--(NOT(ISBLANK('" & R.Worksheet.name & "'!" & R.Address & "))),1)," & NotFoundResult & ")")
    End Function
    

    【讨论】:

    • 效果很好,如果你不限制范围的话会有点慢。如果你想要一个特定的列,我建议使用Sheet.UsedRange.Columns(Col) 之类的东西。
    【解决方案5】:

    我假设 Slothario 的工作表结构简单,具有以下主要特点:

    • A 列中最后填充的单元格也是工作表中最后填充的行(至少在没有隐藏或过滤掉任何行时)。
    • 第 1 行有东西

    在这种情况下,这里有两种简单的方法来识别不同类型的“最后一行”:

    Cells.SpecialCells(xlLastCell).Row 'Last row that is not hidden or filtered out
    
    Activesheet.UsedRange.Rows.Count 'Last row with a value in it (even if the row is hidden; only gives right answer if row 1 is nonblank)
    

    如果顶行可能为空白,则需要将第二个选项修改为:

    Activesheet.UsedRange.Rows.Count + Activesheet.UsedRange.Row -1 'Last row with a value in it (even if the row is hidden)
    

    【讨论】:

    • 不确定您的答案如何贡献 MattCrum 的答案中尚未提供的任何内容 - 这些与他 8 年前描述的方法相同。您是否愿意详细说明为什么您认为需要另一个答案,而不是仅仅发表评论或对之前的答案进行编辑?
    • 我提供了有关 MattCrum 的两种方法有何不同的信息,并针对原始问题中的用例量身定制。我的代表只有 41 岁,我无权在其他人的答案中添加 cmets。至于编辑以前的答案,也许我应该这样做,我不知道这是可能的。感谢您的提示。
    • 没问题。我在审查队列中看到了您对旧问题的新答案的答案。我想我会问,而不是标记 ir 或拒绝投票。感谢您的回复。
    【解决方案6】:

    我一直使用它来获取最后一行,但不是 100% 确定它适用于隐藏单元格:)

    附:确保在测试时更改工作表名称

    'VBA to find last row
    lngLastRow = ThisWorkbook.Worksheets("Data").Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
    

    【讨论】:

      【解决方案7】:
      Public Function lr(ByVal source As Worksheet, colu As Long) As Long
      Dim tmp As Long
      tmp = source.Cells(source.Rows.Count, colu).End(xlUp).Row
      
      While source.Cells(tmp + 1, colu).EntireRow.Hidden = True
      tmp = tmp + 1
      Wend
      lr = tmp
      End Function
      

      【讨论】:

        猜你喜欢
        • 2014-02-22
        • 1970-01-01
        • 1970-01-01
        • 2018-01-04
        • 1970-01-01
        • 2016-03-31
        • 1970-01-01
        • 2022-07-05
        • 1970-01-01
        相关资源
        最近更新 更多