簡體   English   中英

在 Excel VBA 中查找最后使用的單元格

[英]Find last used cell in Excel VBA

當我想找到最后使用的單元格值時,我使用:

Dim LastRow As Long

LastRow = Range("E4:E48").End(xlDown).Row

Debug.Print LastRow

當我將單個元素放入單元格時,我得到了錯誤的 output。 但是當我在單元格中輸入多個值時,output 是正確的。 這背后的原因是什么?

注意:我打算將其設為“一站式帖子”,您可以在其中使用Correct的方式找到最后一行。 這還將涵蓋查找最后一行時要遵循的最佳實踐。 因此,每當我遇到新的場景/信息時,我都會繼續更新它。


找到最后一行的不可靠方法

一些最常見的查找最后一行的方法非常不可靠,因此永遠不應該使用。

  1. 使用范圍
  2. xl向下
  3. 計數A

UsedRange永遠不應該用於查找最后一個有數據的單元格。 這是非常不可靠的。 試試這個實驗。

在單元格A5中鍵入內容。 現在,當您使用下面給出的任何方法計算最后一行時,它會給您 5。現在將單元格A10成紅色。 如果您現在使用以下任何代碼,您仍然會得到 5。如果您使用Usedrange.Rows.Count ,您會得到什么? 不會是5。

這是一個展示UsedRange如何工作的場景。

在此處輸入圖像描述

xlDown同樣不可靠。

考慮這段代碼

lastrow = Range("A1").End(xlDown).Row

如果只有一個單元格( A1 )有數據會發生什么? 您最終將到達工作表中的最后一行! 這就像選擇單元格A1 ,然后按End鍵,然后按向下箭頭鍵。 如果某個范圍內有空白單元格,這也會給您帶來不可靠的結果。

CountA也是不可靠的,因為如果中間有空白單元格,它會給你不正確的結果。

因此,應該避免使用UsedRangexlDownCountA來查找最后一個單元格。


在列中查找最后一行

要查找 Col E 中的最后一行,請使用此

With Sheets("Sheet1")
    LastRow = .Range("E" & .Rows.Count).End(xlUp).Row
End With

如果您注意到我們有一個. Rows.Count之前。 我們經常選擇忽略這一點。 有關您可能遇到的錯誤,請參閱問題。 我總是建議使用. Rows.CountColumns.Count之前。 該問題是代碼將失敗的經典場景,因為Rows.Count對於 Excel 2003 及更早版本返回65536 ,而對於 Excel 2007 及更高版本返回1048576 同樣Columns.Count分別返回25616384

Excel 2007+ 有1048576行的上述事實也強調了這樣一個事實,即我們應該始終將保存行值的變量聲明為Long而不是Integer ,否則您將收到Overflow錯誤。

請注意,此方法將跳過任何隱藏的行。 回顧我上面的 A 列屏幕截圖,如果第 8 行被隱藏,這種方法將返回5而不是8


在工作表中查找最后一行

要在工作表中找到Effective的最后一行,請使用它。 注意Application.WorksheetFunction.CountA(.Cells)的使用。 這是必需的,因為如果工作表中沒有包含數據的單元格,則.Find將為您提供Run Time Error 91: Object Variable or With block variable not set

With Sheets("Sheet1")
    If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
        lastrow = .Cells.Find(What:="*", _
                      After:=.Range("A1"), _
                      Lookat:=xlPart, _
                      LookIn:=xlFormulas, _
                      SearchOrder:=xlByRows, _
                      SearchDirection:=xlPrevious, _
                      MatchCase:=False).Row
    Else
        lastrow = 1
    End If
End With

查找表中的最后一行 (ListObject)

同樣的原則也適用,例如獲取表格第三列的最后一行:

Sub FindLastRowInExcelTableColAandB()
Dim lastRow As Long
Dim ws As Worksheet, tbl as ListObject
Set ws = Sheets("Sheet1")  'Modify as needed
'Assuming the name of the table is "Table1", modify as needed
Set tbl = ws.ListObjects("Table1")

With tbl.ListColumns(3).Range
    lastrow = .Find(What:="*", _
                After:=.Cells(1), _
                Lookat:=xlPart, _
                LookIn:=xlFormulas, _
                SearchOrder:=xlByRows, _
                SearchDirection:=xlPrevious, _
                MatchCase:=False).Row
End With

End Sub

注意:這個答案是由這個評論激發的。 UsedRange的目的與上面答案中提到的不同。

至於找到最后使用的單元格的正確方法,首先要確定什么是已使用的,然后選擇合適的方法 我認為至少三個含義:

  1. Used = 非空白,即有數據

  2. Used = "... in use,表示包含數據或格式的部分。" 根據官方文檔,這是 Excel 在保存時使用的標准。 另請參閱此官方文檔 如果沒有意識到這一點,該標准可能會產生意想不到的結果,但它也可能被有意利用(不太常見,當然),例如,突出或打印最終可能沒有數據的特定區域。 而且,當然,最好將其作為保存工作簿時使用的范圍的標准,以免丟失部分工作。

  3. Used = "... in use,表示包含數據或格式的部分"或條件格式。 與 2. 相同,但也包括作為任何條件格式規則目標的單元格。

如何找到最后使用的單元格取決於想要什么(您的標准)

對於標准 1,我建議閱讀此答案 請注意, UsedRange被引用為不可靠。 我認為這具有誤導性(即,對UsedRange “不公平”),因為UsedRange根本不打算報告包含數據的最后一個單元格。 因此,如該答案所示,在這種情況下不應使用它。 另請參閱此評論

對於標准 2,與同樣為此用途設計的其他選項相比, UsedRange是最可靠的選項 它甚至不需要保存工作簿以確保最后一個單元格已更新。 Ctrl + End將在保存之前轉到錯誤的單元格(“在保存工作表之前不會重置最后一個單元格”,來自http://msdn.microsoft.com/en-us/library/aa139976%28v=office。 10%29.aspx 。這是一個舊參考,但在這方面有效)。

對於標准 3,我不知道任何內置方法 標准 2 不考慮條件格式。 可能有基於公式的格式化單元格,但UsedRangeCtrl + End未檢測到。 在圖中,最后一個單元格是 B3,因為它已明確應用了格式。 單元格 B6:D7 具有從條件格式規則派生的格式,即使UsedRange也檢測不到。 考慮到這一點需要一些 VBA 編程。

在此處輸入圖像描述


至於你的具體問題這背后的原因是什么?

您的代碼使用 E4:E48 范圍內的第一個單元格作為蹦床,用於使用End(xlDown)向下

如果您的范圍內除了第一個以外沒有非空白單元格,則將獲得“錯誤”輸出。 然后,您在黑暗中跳躍,即在工作表中向下跳躍(您應該注意空白字符串和空字符串之間的區別!)。

注意:

  1. 如果您的范圍包含不連續的非空白單元格,那么它也會給出錯誤的結果。

  2. 如果只有一個非空白單元格,但它不是第一個,您的代碼仍然會給您正確的結果。

我創建了這個一站式函數來確定最后一行、最后一列和最后一個單元格,無論是數據、格式化(分組/注釋/隱藏)單元格還是條件格式

Sub LastCellMsg()
    Dim strResult As String
    Dim lngDataRow As Long
    Dim lngDataCol As Long
    Dim strDataCell As String
    Dim strDataFormatRow As String
    Dim lngDataFormatCol As Long
    Dim strDataFormatCell As String
    Dim oFormatCond As FormatCondition
    Dim lngTempRow As Long
    Dim lngTempCol As Long
    Dim lngCFRow As Long
    Dim lngCFCol As Long
    Dim strCFCell As String
    Dim lngOverallRow As Long
    Dim lngOverallCol As Long
    Dim strOverallCell As String

    With ActiveSheet

        If .ListObjects.Count > 0 Then
            MsgBox "Cannot return reliable results, as there is at least one table in the worksheet."
            Exit Sub
        End If

        strResult = "Workbook name: " & .Parent.Name & vbCrLf
        strResult = strResult & "Sheet name: " & .Name & vbCrLf

        'DATA:
        'last data row
        If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
            lngDataRow = .Cells.Find(What:="*", _
             After:=.Range("A1"), _
             Lookat:=xlPart, _
             LookIn:=xlFormulas, _
             SearchOrder:=xlByRows, _
             SearchDirection:=xlPrevious, _
             MatchCase:=False).Row
        Else
            lngDataRow = 1
        End If
        'strResult = strResult & "Last data row: " & lngDataRow & vbCrLf

        'last data column
        If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
            lngDataCol = .Cells.Find(What:="*", _
             After:=.Range("A1"), _
             Lookat:=xlPart, _
             LookIn:=xlFormulas, _
             SearchOrder:=xlByColumns, _
             SearchDirection:=xlPrevious, _
             MatchCase:=False).Column
        Else
            lngDataCol = 1
        End If
        'strResult = strResult & "Last data column: " & lngDataCol & vbCrLf

        'last data cell
        strDataCell = Replace(Cells(lngDataRow, lngDataCol).Address, "$", vbNullString)
        strResult = strResult & "Last data cell: " & strDataCell & vbCrLf

        'FORMATS:
        'last data/formatted/grouped/commented/hidden row
        strDataFormatRow = StrReverse(Split(StrReverse(.UsedRange.Address), "$")(0))
        'strResult = strResult & "Last data/formatted row: " & strDataFormatRow & vbCrLf

        'last data/formatted/grouped/commented/hidden column
        lngDataFormatCol = Range(StrReverse(Split(StrReverse(.UsedRange.Address), "$")(1)) & "1").Column
        'strResult = strResult & "Last data/formatted column: " & lngDataFormatCol & vbCrLf

        'last data/formatted/grouped/commented/hidden cell
        strDataFormatCell = Replace(Cells(strDataFormatRow, lngDataFormatCol).Address, "$", vbNullString)
        strResult = strResult & "Last data/formatted cell: " & strDataFormatCell & vbCrLf

        'CONDITIONAL FORMATS:
        For Each oFormatCond In .Cells.FormatConditions

            'last conditionally-formatted row
            lngTempRow = CLng(StrReverse(Split(StrReverse(oFormatCond.AppliesTo.Address), "$")(0)))
            If lngTempRow > lngCFRow Then lngCFRow = lngTempRow

            'last conditionally-formatted column
            lngTempCol = Range(StrReverse(Split(StrReverse(oFormatCond.AppliesTo.Address), "$")(1)) & "1").Column
            If lngTempCol > lngCFCol Then lngCFCol = lngTempCol
        Next
        'no results are returned for Conditional Format if there is no such
        If lngCFRow <> 0 Then
            'strResult = strResult & "Last cond-formatted row: " & lngCFRow & vbCrLf
            'strResult = strResult & "Last cond-formatted column: " & lngCFCol & vbCrLf

            'last conditionally-formatted cell
            strCFCell = Replace(Cells(lngCFRow, lngCFCol).Address, "$", vbNullString)
            strResult = strResult & "Last cond-formatted cell: " & strCFCell & vbCrLf
        End If

        'OVERALL:
        lngOverallRow = Application.WorksheetFunction.Max(lngDataRow, strDataFormatRow, lngCFRow)
        'strResult = strResult & "Last overall row: " & lngOverallRow & vbCrLf
        lngOverallCol = Application.WorksheetFunction.Max(lngDataCol, lngDataFormatCol, lngCFCol)
        'strResult = strResult & "Last overall column: " & lngOverallCol & vbCrLf
        strOverallCell = Replace(.Cells(lngOverallRow, lngOverallCol).Address, "$", vbNullString)
        strResult = strResult & "Last overall cell: " & strOverallCell & vbCrLf

        MsgBox strResult
        Debug.Print strResult

    End With

End Sub

結果如下所示:
確定最后一個單元格

要獲得更詳細的結果,可以取消注釋代碼中的某些行:
最后一列,行

存在一個限制 - 如果工作表中有表格,結果可能會變得不可靠,因此我決定避免在這種情況下運行代碼:

If .ListObjects.Count > 0 Then
    MsgBox "Cannot return reliable results, as there is at least one table in the worksheet."
    Exit Sub
End If

使用該解決方案時要記住的一個重要注意事項...

LastRow = ws.Cells.Find(What:="*", After:=ws.range("a1"), SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row

...是為了確保您的LastRow變量是Long類型:

Dim LastRow as Long

否則,在 .XLSX 工作簿中的某些情況下,您最終會遇到 OVERFLOW 錯誤

這是我在各種代碼使用中的封裝函數。

Private Function FindLastRow(ws As Worksheet) As Long
    ' --------------------------------------------------------------------------------
    ' Find the last used Row on a Worksheet
    ' --------------------------------------------------------------------------------
    If WorksheetFunction.CountA(ws.Cells) > 0 Then
        ' Search for any entry, by searching backwards by Rows.
        FindLastRow = ws.Cells.Find(What:="*", After:=ws.range("a1"), SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
    End If
End Function

由於最初的問題是關於找到最后一個單元格的問題,因此在這個答案中,我將列出可以獲得意外結果的各種方法 請參閱我對“如何使用宏在 Excel 工作表中找到包含數據的最后一行?”的回答。 我對解決這個問題的看法。

我將首先擴展sancho.s 的答案和 GlennFromIowa 的評論,添加更多細節:

[...] 首先要決定什么被認為是使用的。 我看到至少6個意思。 細胞有:

  • 1) 數據,即公式,可能會產生空值;
  • 2)一個值,即一個非空白公式或常數;
  • 3) 格式化;
  • 4) 條件格式;
  • 5)與單元格重疊的形狀(包括評​​論);
  • 6)參與一個表(列表對象)。

您要測試哪種組合? 有些(例如表格)可能更難測試,有些可能很少見(例如超出數據范圍的形狀),但其他可能會因情況而異(例如,具有空白值的公式)。

您可能需要考慮的其他事項:

  • A) 可以有隱藏行(例如自動過濾器)、空白單元格或空白行嗎?
  • B) 什么樣的表現是可以接受的?
  • C) VBA 宏能否以任何方式影響工作簿或應用程序設置?

考慮到這一點,讓我們看看獲取“最后一個單元格”的常用方法如何產生意想不到的結果:

  • 問題中的.End(xlDown)代碼最容易中斷(例如,使用單個非空單元格或中間有空白單元格時),原因在此處Siddharth Rout 的回答中解釋了原因(搜索“xlDown is equals不可靠。” )👎
  • 任何基於Count ing( CountACells*.Count )或.CurrentRegion的解決方案也會在出現空白單元格或行時中斷👎
  • 涉及.End(xlUp)從列末尾向后搜索的解決方案將與 CTRL+UP 一樣,在可見行中查找數據(產生空白值的公式被視為“數據”)(因此在啟用自動過濾器的情況下使用它)可能會產生不正確的結果⚠️)。

    您必須注意避免標准陷阱(有關詳細信息,我將在此處再次參考Siddharth Rout 的答案,查找“查找列中的最后一行”部分),例如硬編碼最后一行( Range("A65536").End(xlUp) ) 而不是依賴sht.Rows.Count

  • .SpecialCells(xlLastCell)等價於 CTRL+END,返回“已使用范圍”的最底部和最右側單元格,因此適用於依賴“已使用范圍”的所有注意事項也適用於此方法。 此外,“使用范圍”僅在保存工作簿和訪問worksheet.UsedRange時重置,因此xlLastCell可能會產生陳舊的結果⚠️ 未保存的修改(例如,在刪除某些行之后)。 請參閱dotNET 附近的答案
  • sht.UsedRange (在sancho.s 的答案中詳細描述)考慮數據和格式(盡管不是條件格式)並重置工作表的“使用范圍” ,這可能是您想要的,也可能不是您想要的。

    注意一個常見的錯誤️是使用.UsedRange.Rows.Count ⚠️,它返回的是已用范圍內的數,而不是最后的行數(如果前幾行為空白,它們會有所不同),詳情見newguy的回答如何使用宏在 Excel 工作表中找到包含數據的最后一行?

  • .Find允許您在任何列中查找包含任何數據(包括公式)或非空白值的最后一行。 您可以選擇是否對公式或值感興趣,但問題是它會重置 Excel 查找對話框中的默認值️️⚠️,這可能會讓您的用戶非常困惑。 它還需要小心使用,請參閱Siddharth Rout 的答案here( “Find Last Row in a Sheet”部分)
  • 在循環中檢查單個Cells ' 的更明確的解決方案通常比重新使用 Excel 函數慢(盡管仍然可以是高性能的),但讓您准確指定您想要查找的內容。 請參閱基於UsedRange和 VBA 數組的解決方案,以查找給定列中包含數據的最后一個單元格——它處理隱藏行、過濾器、空白,不修改 Find 默認值並且非常高效。

無論您選擇哪種解決方案,都要小心

  • 使用Long而不是Integer來存儲行號(以避免出現超過 65k 行的Overflow )和
  • 始終指定您正在使用的工作表(即Dim ws As Worksheet ... ws.Range(...)而不是Range(...)
  • 使用.Value (這是一個Variant )時避免像.Value <> ""這樣的隱式強制轉換,因為如果單元格包含錯誤值,它們將失敗。

我要補充 Siddarth Rout 給出的答案,說可以通過讓 Find 返回 Range 對象而不是行號來跳過 CountA 調用,然后測試返回的 Range 對象以查看它是否為 Nothing(空白工作表) .

另外,我會讓我的任何 LastRow 過程版本為空白工作表返回零,然后我可以知道它是空白的。

我想知道沒有人提到這一點,但獲取最后使用的單元格的最簡單方法是:

Function GetLastCell(sh as Worksheet) As Range
    GetLastCell = sh.Cells(1,1).SpecialCells(xlLastCell)
End Function

這實質上返回的單元格與您在選擇 Cell A1后通過Ctrl + End獲得的單元格相同。

提醒一句:Excel 會跟蹤曾經在工作表中使用過的最右下角的單元格。 因此,例如,如果您在B3中輸入內容,在H8中輸入其他內容,然后刪除H8的內容,則按Ctrl + End仍會將您帶到H8單元格。 上述函數將具有相同的行為。

於 2021 年底更新

有了 Excel 的新計算引擎和數組功能,以及過濾器功能,我相信這個話題現在應該少很多爭議,並且以下選項提供了速度、可靠性和簡單性的最佳組合(過去已證明難以平衡,因為這里的眾多帖子說明了)。

此外,我將last used定義為不是isBlank函數定義的空白。

Excel公式

首先,請注意,過濾器函數使得使用以下公式獲取最后一個單元格變得更加簡單,用於特定的行或列(在這些情況下為Column ARow 1 ):

=MAX(FILTER(ROW(A:A),NOT(ISBLANK(A:A))))
=MAX(FILTER(COLUMN(1:1),NOT(ISBLANK(1:1))))

最后一行特定范圍的 VBA 函數

使用上述函數,我們可以將其轉換為 VBA 函數,但通過限制范圍使其更快,同時通過執行多個列來擴展其功能(感謝Chris Neilsen的即時反饋 tweeking/建議)。 我還發現,通過將每一列限定為僅比前一行高一行的范圍,我發現了速度的巨大提升。

Function FindLastRowInRange(someColumns As Range) As Long
Const zFx = "=MAX(FILTER(ROW(????),NOT(ISBLANK(????)),0))"
   
   Dim tRng As Range, i As Long, tRow As Long, pRng As Range
   With someColumns.Worksheet
      Set tRng = Intersect(someColumns.EntireColumn, .UsedRange)
      
      For i = 1 To tRng.Columns.Count
         
         Set pRng = Intersect(tRng.Columns(i), _
         Range(.Rows(FindLastRowInRange + 1), .Rows(.Rows.Count)))
         
         If Not pRng Is Nothing Then
            tRow = .Evaluate(Replace(zFx, "????", _
               pRng.Address, 1, -1))
         
            If tRow > FindLastRowInRange Then _
               FindLastRowInRange = tRow
            
         End If
      Next i
   End With
End Function

工作表中最后一行的 VBA 函數

要考慮整個工作表(所有列),我建議使用引用前一個的不同 VBA 公式,但它是一個Volatile Function 這可確保公式隨着工作表的任何更改而更新。 顯然,可以將這兩個公式結合起來,但我更喜歡限制 volatile 函數的使用。

Function FindLastRowInSheet(anywhereInSheet As Range) As Long
      Application.Volatile
      FindLastRowInSheet = FindLastRowInRange(anywhereInSheet.Worksheet.UsedRange)
End Function

與其他選項相比的優勢

  • 允許工作表中的某些或所有行/列而不改變方法。
  • 不可能像xlup一樣丟失隱藏行
  • 忽略格式化/使用范圍問題。
  • 不干擾用戶的Find設置。
  • 使用比 VBA 計算更快的工作表功能。
  • 沒有計數細胞(性能豬)。

希望這能結束辯論,但如果有人發現這方面的弱點,請分享。

sub last_filled_cell()
msgbox range("A65536").end(xlup).row
end sub

在這里, A65536是 A 列中的最后一個單元格,此代碼在 excel 2003 上進行了測試。

然而,這個問題正在尋求使用 VBA 找到最后一行,我認為最好為工作表函數包含一個數組公式,因為它經常被訪問:

{=ADDRESS(MATCH(INDEX(D:D,MAX(IF(D:D<>"",ROW(D:D)-ROW(D1)+1)),1),D:D,0),COLUMN(D:D))}

您需要輸入不帶括號的公式,然后按Shift + Ctrl + Enter使其成為數組公式。

這將為您提供 D 列中最后使用的單元格的地址。


感謝pgsystemtester ,這將為您提供最后使用的單元格的行號:

{=MATCH(INDEX(D:D,MAX(IF(D:D<>"",ROW(D:D)-ROW(D1)+1)),1),D:D,0)}

我正在尋找一種模仿CTRL + Shift + End的方法,所以 dotNET 解決方案很棒,除了我的 Excel 2010,如果我想避免錯誤,我需要添加一個set

Function GetLastCell(sh As Worksheet) As Range
  Set GetLastCell = sh.Cells(1, 1).SpecialCells(xlLastCell)
End Function

以及如何自己檢查:

Sub test()
  Dim ws As Worksheet, r As Range
  Set ws = ActiveWorkbook.Sheets("Sheet1")
  Set r = GetLastCell(ws)
  MsgBox r.Column & "-" & r.Row
End Sub
Sub lastRow()

    Dim i As Long
        i = Cells(Rows.Count, 1).End(xlUp).Row
            MsgBox i

End Sub

sub LastRow()

'Paste & for better understanding of the working use F8 Key to run the code .

dim WS as worksheet
dim i as long

set ws = thisworkbook("SheetName")

ws.activate

ws.range("a1").select

ws.range("a1048576").select

activecell.end(xlup).select

i= activecell.row

msgbox "My Last Row Is " & i

End sub

在過去 3 年多的時間里,這些是我用來查找每個定義的列(對於行)和行(對於列)的最后一行和最后一列的函數:

最后一欄:

Function lastCol(Optional wsName As String, Optional rowToCheck As Long = 1) As Long

    Dim ws  As Worksheet

    If wsName = vbNullString Then
        Set ws = ActiveSheet
    Else
        Set ws = Worksheets(wsName)
    End If

    lastCol = ws.Cells(rowToCheck, ws.Columns.Count).End(xlToLeft).Column

End Function

最后一行:

Function lastRow(Optional wsName As String, Optional columnToCheck As Long = 1) As Long

    Dim ws As Worksheet

    If wsName = vbNullString Then
        Set ws = ActiveSheet
    Else
        Set ws = Worksheets(wsName)
    End If

    lastRow = ws.Cells(ws.Rows.Count, columnToCheck).End(xlUp).Row

End Function

對於 OP,這是獲取E列最后一行的方法:

Debug.Print lastRow(columnToCheck:=Range("E4:E48").Column)

最后一行,用數據計算空行:

在這里我們可以使用眾所周知的 Excel 公式,它為我們提供 Excel 中工作表的最后一行,而不涉及 VBA - =IFERROR(LOOKUP(2,1/(NOT(ISBLANK(A:A))),ROW(A:A)),0)

為了把它放在 VBA 中而不是在 Excel 中寫任何東西,使用后面函數的參數,可以考慮這樣的事情:

Public Function LastRowWithHidden(Optional wsName As String, Optional columnToCheck As Long = 1) As Long

    Dim ws As Worksheet

    If wsName = vbNullString Then
        Set ws = ActiveSheet
    Else
        Set ws = Worksheets(wsName)
    End If

    Dim letters As String
    letters = ColLettersGenerator(columnToCheck)
    LastRowWithHidden = ws.Evaluate("=IFERROR(LOOKUP(2,1/(NOT(ISBLANK(" & letters & "))),ROW(" & letters & " )),0)")

End Function

Function ColLettersGenerator(col As Long) As String

    Dim result As Variant
    result = Split(Cells(1, col).Address(True, False), "$")
    ColLettersGenerator = result(0) & ":" & result(0)

End Function

當我想找到最后使用的單元格值時,我使用:

Dim LastRow As Long

LastRow = Range("E4:E48").End(xlDown).Row

Debug.Print LastRow

當我將單個元素放入單元格時,我得到了錯誤的輸出。 但是當我在單元格中放入多個值時,輸出是正確的。 這背后的原因是什么?

常規范圍或表中的最后一行 (ListObject)

  1. 如果范圍是常規范圍或表格(列表對象),則查找最后一行需要使用不同的方法。
  2. 查找表中的最后一行需要指定其他參數(表名,列相對於第一個表列的位置)。

無論范圍類型如何,我都為最后一行創建了這個通用函數。 只要給它任何單元格引用,它就會返回最后一行。 知道范圍特征沒有任何麻煩,特別是如果您的范圍有時是常規范圍,有時是 ListObject。 在表上使用常規范圍方法可能會返回錯誤的結果。 當然,您可以提前計划並每次都使用正確的方法,但是如果您可以使用通用功能,為什么還要麻煩呢?

 Sub RunMyLastRow() Dim Result As Long Result = MyLastRow(Worksheets(1).Range("A1")) End Sub
    Function MyLastRow(RefrenceRange As Range) As Long
    Dim WS As Worksheet
    Dim TableName As String
    Dim ColNumber As Long
    Dim LastRow As Long
    Dim FirstColumnTable As Long
    Dim ColNumberTable As Long
    Set WS = RefrenceRange.Worksheet
    TableName = GetTableName(RefrenceRange)
    ColNumber = RefrenceRange.Column
    
    ''If the table (ListObject) does not start in column "A" we need to calculate the 
    ''first Column table and how many Columns from its beginning the Column is located.
    If TableName <> vbNullString Then
     FirstColumnTable = WS.ListObjects(TableName).ListColumns(1).Range.Column
     ColNumberTable = ColNumber - FirstColumnTable + 1
    End If 

    If TableName = vbNullString Then
    LastRow = WS.Cells(WS.Rows.Count, ColNumber).End(xlUp).Row
    Else
    LastRow = WS.ListObjects(TableName).ListColumns(ColNumberTable).Range.Find( _
               What:="*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
    End If
    MyLastRow = LastRow
    End Function
    
 ''Get Table Name by Cell Range Function GetTableName(RefrenceRange As Range) As String If RefrenceRange.ListObject Is Nothing Then GetTableName = vbNullString Else GetTableName = RefrenceRange.ListObject.Name End If End Function

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM