VBAを使用するExcelで最後に使用されたセルを見つける際のエラー


179

最後に使用したセルの値を見つけたいときは、次のようにします。

Dim LastRow As Long

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

Debug.Print LastRow

単一の要素をセルに入れると、間違った出力が出ます。しかし、セルに複数の値を入力すると、出力は正しくなります。この背後にある理由は何ですか?


回答:


309

:私は、これを「ワンストップポスト」にCorrectして、最後の行を見つける方法を使用できるようにするつもりです。これは、最後の行を見つけるときに従うべきベストプラクティスもカバーします。したがって、新しいシナリオや情報に遭遇した場合は、常に更新を続けます。


最後の行を見つける信頼できない方法

非常に信頼性が低く、したがって使用してはならない最後の行を見つける最も一般的な方法のいくつか。

  1. 使用範囲
  2. xlDown
  3. CountA

UsedRange必要があります決してデータを持っている最後のセルを検索するために使用しないこと。それは非常に信頼できません。この実験を試してください。

セルに何かを入力しますA5。ここで、以下のいずれかの方法で最後の行を計算すると、5が得られます。今度はセルをA10赤に着色します。以下のコードのいずれかを使用しても、5が引き続き取得されます。Usedrange.Rows.Count何を使用すると、何が得られますか?5にはなりません。

これがどのようにUsedRange機能するかを示すシナリオです。

ここに画像の説明を入力してください

xlDown 同様に信頼できません。

このコードを検討してください

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

A1データを持つセル()が1つだけの場合はどうなりますか?ワークシートの最後の行に到達することになります!セルA1を選択してEndキーを押してからキーを押すようDown Arrowなものです。また、範囲内に空白のセルがある場合、信頼性の低い結果が得られます。

CountA また、間に空白のセルがあると誤った結果が得られるため、信頼性が低くなります。

そしてそれゆえ一つはの使用は避けるべきであるUsedRangexlDownCountA最後のセルを見つけること。


列の最後の行を見つける

列Eの最後の行を見つけるには、これを使用します

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

.以前に気づいた場合Rows.Count。私たちはしばしばそれを無視することを選びました。発生する可能性のあるエラーについては、この質問を参照してください。私はいつも使用して助言する.前に、Rows.CountColumns.Count。この質問は、Excel 2003以前およびExcel 2007以降で結果Rows.Countが返さ65536れるためにコードが失敗するという典型的なシナリオ1048576です。同様Columns.Count25616384をそれぞれ返します。

エクセル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)

同じ原則が適用されます。たとえば、テーブルの3番目の列の最後の行を取得します。

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

9
@phan:セルA5に何かを入力します。上記のいずれかの方法で最後の行を計算すると、5になります。今度はセルA10を赤に着色します。上記のコードのいずれかを使用しても、5が引き続き取得されます。Usedrange.Rows.Count何を使用すると、何が得られますか?5にはなりません。usedrangeは、最後の行を見つけるのに非常に信頼性が低くなります。
Siddharth Rout 2012

6
残念ながら、.Findは[検索]ダイアログでユーザーの設定を台無しにしてしまいます。つまり、Excelにはダイアログの設定が1つしかなく、.Findを使用するとそれらが置き換えられます。別のトリックは、UsedRangeを引き続き使用することですが、正しい最大値を決定する絶対(ただし信頼できない)最大値として使用します。
Carl Colijn、2014年

4
@CarlColijn:めちゃくちゃだとは思いません。:) Excelは単にremembers最後の設定です。手動でを実行した場合でもFind、最後の設定が記憶されます。これは、この「事実」を知っていれば実際には朗報です
Siddharth Rout

3
@KeithPark:先に進んでください:)知識はそれが広がった場合にのみ意味を持ちます:)
Siddharth Rout

9
UsedRangeデータのある最後のセルを見つけるのは非常に信頼できない)というあなたの説明は誤解を招くと思います。UsedRange場合によっては正しい結果が得られることもありますが、単にその目的を意図したものではありません。提案された実験は混乱を増すと思います。UsedRange($ A $ 1:$ A $ 8)で得られる結果は、最初にデータを入力して削除することに依存しません。右側の図は、データを入力して削除しなくても同じです。私の答えを見てください。
sancho.s ReinstateMonicaCellio 2014

34

注:この回答は、このコメントによって動機付けられました。の目的はUsedRange、上記の回答で述べられているものとは異なります。

最後に使用されたセルを見つける正しい方法については、最初に使用されていると見なされるものを決定し、次に適切な方法を選択する必要があります。少なくとも3つの意味があると思います。

  1. 使用済み=空白ではない、つまりデータがある

  2. 使用済み= "...使用中、つまりデータまたはフォーマットを含むセクションを意味します。" 公式文書によると、これは保存時にExcelで使用される基準です。この公式ドキュメントも参照してください。これに気付いていない場合、この基準は予期しない結果をもたらす可能性がありますが、意図的に悪用されることもあります(頻度は低く、確実ではありません)。そしてもちろん、ワークブックの保存時に使用する範囲の基準として、自分の作業の一部を失わないようにすることが望ましいです。

  3. 使用済み= "...使用中、つまりデータまたはフォーマットを含むセクション" または条件付きフォーマット。 2.と同じですが、条件付き書式ルールのターゲットであるセルも含まれます。

最後に使用セルが何に依存してどのように見つけるかあなたは(あなたの基準を)したいです

基準1については、この回答を読むことをお勧めしますUsedRangeは信頼できないものとして引用されていることに注意してください。データを含む最後のセルを報告することを単に意図していないのでUsedRange、それは誤解を招く(つまり、「への不公平」)だと思いUsedRangeます。したがって、その回答に示されているように、この場合は使用しないでください。このコメントも参照してください。

基準2では、UsedRangeこれもこの用途向けに設計された他のオプションと比較して、最も信頼できるオプションです。最後のセルが確実に更新されるように、ブックを保存する必要もありません。 Ctrl+ End保存する前に間違ったセルに移動します(「最後のセルはワークシートを保存するまでリセットされません」、http://msdn.microsoft.com/en-us/library/aa139976%28v=office.10%から 29.aspx。これは古いリファレンスですが、この点では有効です)。

基準3については、組み込みの方法を知りません。基準2は条件付き書式を考慮していません。UsedRangeまたはCtrl+で検出されない数式に基づいてセルをフォーマットした可能性がありますEnd。図では、書式設定が明示的に適用されているため、最後のセルはB3です。セルB6:D7には条件付き書式ルールから派生した書式があり、これもによって検出されませんUsedRange。これを説明するには、いくつかのVBAプログラミングが必要です。

ここに画像の説明を入力してください


あなたの特定の質問についてこれの背後にある理由は何ですか?

コードは、範囲E4:E48の最初のセルをトランポリンとして使用し、でジャンプEnd(xlDown)ます。

「誤った」出力は、おそらく最初のもの以外の範囲内に空白でないセルがない場合に取得されます。次に、暗闇の中で、つまりワークシートを下に跳んでいます(空白空の文字列の違いに注意してください!)。

ご了承ください:

  1. 範囲に隣接していない空白でないセルが含まれている場合も、誤った結果になります。

  2. 空白でないセルが1つしかなく、それが最初のセルではない場合でも、コードは正しい結果を提供します。


3
何が使用されていると見なされるかを最初に決定する必要があることに同意します。私は少なくとも6つの意味を見ます。セルには次のものが含まれます。2)値、つまり空白でない式または定数。3)フォーマット; 4)条件付きフォーマット。5)セルと重なる形状(コメントを含む)。6)テーブル(リストオブジェクト)への関与。どの組み合わせをテストしますか?いくつか(テーブルなど)はテストがより難しく、いくつかはまれ(データ範囲外の形状など)かもしれませんが、その他は状況に応じて変化する可能性があります(たとえば、値が空白の数式)。
GlennFromIowa

20

データ、フォーマット済み(グループ化/コメント/非表示)セル、条件​​付きフォーマットなど、最後の行、列、セル決定するためのこのワンストップ関数を作成しました。

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

結果は次のようになります。
最後のセルを決定

より詳細な結果を得るには、コードの一部の行のコメントを解除できます。
最後の列、行

制限が1つあります。シートにテーブルがあると、結果が信頼できなくなる可能性があるため、この場合はコードを実行しないようにします。

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

2
@franklin-私はちょうどあなたの修正を含む受信トレイのメッセージに気づきました。これはレビュアーによって拒否されました。私はその間違いを修正しました。この機能は必要なときに一度使用しましたが、再び使用する予定なので、本当にありがとうございます。
ZygD 2016

11

ソリューションを使用する際の注意点...

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

8

Siddarth Routの回答に、Findで行番号ではなくRangeオブジェクトを返すことでCountA呼び出しをスキップできることを追加し、返されたRangeオブジェクトをテストしてNothing(空白のワークシート)かどうかを確認します。

また、私は任意のLastRowプロシージャのバージョンで空白のワークシートに対してゼロを返すようにしているので、それが空白であることがわかります。


8

誰もこれについて言及していませんが、最後に使用されたセルを取得する最も簡単な方法は次のとおりです。

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

これは基本的に、Cellを選択した後にCtrl+で取得した同じセルを返します。EndA1

注意:Excelは、ワークシートで使用された最も右下のセルを追跡します。したがって、たとえば、B3に何かを入力し、H8に何かを入力して、後でH8の内容を削除した場合でも、Ctrl+ Endを押すとH8セルに移動します。上記の関数は同じ動作をします。


2
Last CellExcelではUsed RangeLast Used Cell;)とは異なる空のセル(から)を参照することがあります。
shA.t 2015

1
OPは最後の行だけを必要としましたが、そうです、最後のセルはH5でなければなりません。しかし、あなたは内の値を削除した後、あなたの機能をテストすることができA5あなたが最後のセルは、その空のセルであることがわかります、と私はあなたのコードは、そのようないくつかの編集必要だと思いますCells(1,1).Select()、それは多分ある無効ですActiveSheet.Cells(1,1).Select。また、VBAではSelect;)の使用は推奨されません。
shA.t 2015

5
これは、Excel VBAの2つの基本的なルールに違反します。選択を使用しないでください!また、必要なシートがアクティブなシートであるとは限りません。
レイチェルヘッティンガー、2015年

1
これは古い答えですが、がありませんSet
BigBen

8

元の質問は最後のセルの検索に関する問題なので、この回答では、予期しない結果を得ることができるさまざまな方法をリストします「マクロを使用してExcelシートのデータを含む最後の行を見つけるにはどうすればよいですか?」に対する私の回答を参照しくださいこれを解決するための私の見解のために。

私は、上に拡大することから始めましょうsancho.sによって解答GlennFromIowaによってコメントにも詳細を追加し、:

[...]最初に何が使用されていると見なされるかを決定する必要があります。私は少なくとも6つの意味を見ます。セルは:

  • 1)データ、つまり数式。結果として空白になる可能性があります。
  • 2)値、つまり空白でない式または定数。
  • 3)フォーマット;
  • 4)条件付きフォーマット。
  • 5)セルと重なる形状(コメントを含む)。
  • 6)テーブル(リストオブジェクト)への関与。

どの組み合わせをテストしますか?いくつか(テーブルなど)はテストがより難しく、いくつかはまれ(データ範囲外の形状など)かもしれませんが、その他は状況(例:値が空白の数式)によって異なる場合があります。

あなたが考慮したいと思うかもしれない他のもの:

  • A)非表示の行(オートフィルターなど)、空白のセル、空白の行はありますか?
  • B)どのようなパフォーマンスが許容されますか?
  • C)VBAマクロは、ワークブックまたはアプリケーション設定に何らかの影響を与える可能性がありますか?

それを念頭に置いて、「最後のセル」を取得する一般的な方法が予期しない結果どのように生成できるかを見てみましょう

  • .End(xlDown)質問のコードは、ここのSiddharth Routの回答で説明されいる理由により(たとえば、1つの空でないセルがある場合、または間に空白のセルがある場合)、簡単に破損します(「xlDownも同様に信頼できない」を検索します)。👎
  • Counting(CountAまたはCells*.Count)に基づくソリューション、または.CurrentRegion空白のセルまたは行があると破損する👎
  • .End(xlUp)列の末尾から逆方向に検索するソリューションでは、CTRL + UPと同様に、表示されている行でデータ(空白の値を生成する式は「データ」と見なされます)を探します(オートフィルターを有効にして使用すると、誤った結果が生成される可能性があります⚠️ )。

    最後の行をハードコーディングするなど、標準の落とし穴を回避するよう注意する必要があります(詳細については、ここでSiddharth Routの回答を再度参照します。「列の最後の行を検索」セクション探してくださいRange("A65536").End(xlUp))。に依存する代わりにsht.Rows.Count

  • .SpecialCells(xlLastCell)CTRL + ENDと同じで、「使用範囲」の一番下のセルと右端のセルを返します。したがって、「使用範囲」に依存することに適用されるすべての警告は、このメソッドにも適用されます。さらに、「使用範囲」は、ワークブックを保存するときとにアクセスするときにのみリセットされるためworksheet.UsedRangexlLastCell変更が保存されていない(たとえば、一部の行が削除された後など)で古い結果が生じる可能性があります。dotNETによる近くの回答を参照してください。
  • sht.UsedRange(ここのsancho.sによる回答で詳細に説明されています)は、データとフォーマットの両方(条件付きフォーマットではありません)を考慮し、ワークシートの「使用範囲」をリセットします。

    注よくある間違いは、使用に️isことを.UsedRange.Rows.Count返す⚠️、行数を使用範囲ではなく、最後の行番号は、詳細に関しては、(最初の数行が空白の場合、彼らは異なります)にnewguyの答えを私は見つけることができますどのようにマクロを含むExcelシートのデータを含む最後の行?

  • .Find任意のデータ(数式を含む)または任意の列の空白以外の値を含む最後の行を検索できます。数式と値のどちらに関心があるかを選択できますが、問題は、Excelの[検索]ダイアログ ️️⚠️ のデフォルトをリセットすることです。これは、ユーザーを混乱させる可能性があります。また、慎重に使用する必要があります。ここのSiddharth Routの回答を参照しください(「シートの最後の行を検索する」セクション)
  • Cellsループで 'を個別にチェックするより明示的なソリューションは、一般にExcel関数を再利用するよりも低速です(ただし、パフォーマンスは向上します)が、検索対象を正確に指定できます。指定された列のデータを含む最後のセルを見つけるには、およびVBA配列に基づく私のソリューションを参照しくださいUsedRange-非表示の行、フィルター、空白を処理し、Findのデフォルトを変更せず、非常に高いパフォーマンスを発揮します。

どんな解決策を選ぶにせよ、注意してください

  • 行番号を格納するLong代わりに使用するIntegerOverflow65,000行を超えることを避けるため)および
  • 常に作業中のワークシートを指定する(つまりのDim ws As Worksheet ... ws.Range(...)代わりにRange(...)
  • 使用しているとき.Value(あるVariant)のような暗黙のキャスト避ける.Value <> ""セルがエラー値が含まれている場合、彼らは失敗しますように。

4

ただし、この質問は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で最後に使用されたセルのアドレスが表示されます。


1
私はこれが好き。行番号のみを取得するように少し変更する場合があります... '{= MATCH(INDEX(D:D、MAX(IF(D:D <> ""、ROW(D:D)-ROW(D1)+1)) 、1)、D:D、0)} '
PGSystemTester '28

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

ここでは、A65536このコードは、Excel 2003の上でテストされた列Aの最後のセルです。


あなたのコードがこの古い質問にどのように答えるかを説明できますか?
2015年

1
この答えはおそらく正しいと便利ですが、問題の解決にどのように役立つかを説明するためにいくつかの説明含めることが望ましいです。これは、動作が停止する原因となる変更(おそらく無関係)があり、ユーザーが一度動作した方法を理解する必要がある場合、将来的に特に役立ちます。
ケビンブラウン

2

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

1

これが私の2セントです。

私見では、データが除外された非表示の行のリスクは非常に大きいためxlUpワンストップの回答と見なすことはできません。私はそれが単純でほとんどの場合うまくいくことに同意しますが、警告なしに最後の行を過小評価するリスクを提示します。これは、スタックオーバーローにジャンプし、この値を取得するための「確実な方法」を模索していた人にとって、いくつかの点でCATASTROPHICの結果を生成する可能性があります。

このFind方法は完璧であり、私はそれをワンストップ回答として承認します。ただしFind、特にこれがUDFの一部である場合は、設定を変更することの欠点が煩わしい場合があります。

投稿された他の回答は問題ありませんが、複雑さが少し過剰になります。したがって、ここでは、信頼性、最小限の複雑さ、およびを使用しないことのバランスを見つけるための私の試みを示しますFind

Function LastRowNumber(Optional rng As Range) As Long

If rng Is Nothing Then
    Set rng = ActiveSheet.UsedRange
Else
    Set rng = Intersect(rng.Parent.UsedRange, rng.EntireColumn)
    If rng Is Nothing Then
        LastRowNumber = 1
        Exit Function
    ElseIf isE = 0 Then
        LastRowNumber = 1
        Exit Function

    End If

End If

LastRowNumber = rng.Cells(rng.Rows.Count, 1).Row

Do While IsEmpty(Intersect(rng, _
    rng.Parent.Rows(LastRowNumber)))

    LastRowNumber = LastRowNumber - 1
Loop

End Function

なぜこれが良いのか:

  • かなり単純で、変数は多くありません。
  • 複数の列を許可します。
  • Find設定を変更しません
  • 列全体を選択した状態でUDFとして使用する場合は動的。

なぜこれが悪いのか:

  • データのセットが非常に大きく、使用された範囲と指定された列の最後の行との間に大きなギャップがあるため、パフォーマンスが低下し、まれに著しく遅くなります。

ただし、find設定をめちゃくちゃにするか、パフォーマンスが低下するという欠点のあるワンストップソリューションの方が、全体的なソリューションとしては優れていると思います。次に、ユーザーは設定をいじくり回して、コードで何が行われているのかを理解しながら、改善を試みることができます。を使用xLUpしても、潜在的なリスクが警告されることはなく、コードが正しく機能していないことを知らないことを誰が知っているかについて、彼らは引き継ぐことができます。


1

過去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の場合、これはcolumnの最後の行を取得する方法Eです。

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

最後の行、データのある空の行を数えます:

ここでは、VBAを使用せずに、Excelのワークシートの最後の行を取得する、よく知られたExcelの数式を使用できます-=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

最後の行/列が非表示の場合、これは誤った結果を返します。
PGSystemTester

@PGSystemTester-はい、しかし私の理解では、それをプログラムするとき、それが非表示の場合、必要な最後の列/行ではありません。
Vityata

うまくいきました。あなたの状況は典型的なユースケースではないと思います。最後の行を必要とするクライアントで作業する場合、より頻繁に、データが表示されている最も低いセルではなく、データが含まれている最も低いセルが検索されます。とにかく...それが機能してうれしい。👍
PGSystemTester

@PGSystemTester-私はあなたの要点を理解しましたが、構造に注意を払い、目に見えないセルを許可しないことは魅力のように機能します。
Vityata

@PGSystemTester-ええ、タスクが空の行を許可する可能性がある場合、おそらくEVAL()有名なExcel式を使用します。人々はそれEval()を悪だと思うかもしれませんが、これは書くべきもう一つの興味深い話です...
Vityata '29

0
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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.