VBAの最終行取得は、必ず埋まる列が1つある表なら Cells(Rows.Count, 列).End(xlUp).Row、どの列にも空白がありうる表なら Find でシートの後ろから検索する、の2つを使い分けます。 取得方法はほかにもあり、それぞれ「何を最後とみなすか」が違います。

この記事では、7つの方式が同じ表でどの行を返すかを条件別の早見表にまとめ、そのまま貼って使える最終行・最終列の関数を載せます。

確認環境:Microsoft Learn の Excel VBA リファレンス(Range.End、Worksheet.UsedRange、Range.CurrentRegion、Range.Find、Range.SpecialCells、Range.MergeArea、ListObject、ListRows、Worksheet.FilterMode、Worksheet.ShowAllData、Integer・Long データ型、Overflow (Error 6))と Microsoft サポートの「ワークシートの最後のセルを特定してリセットする」を 2026-10-06 に開いて確認しました。「結果」を付けたコードと早見表の行番号は、LibreOffice 24.2.7.2(Linux)の Basic を VBA 互換モード(Option VBASupport 1)にして動かした値です。

この記事の結論

  • 1列が必ず埋まる表(No や ID の列がある表)は、その列で ws.Cells(ws.Rows.Count, 列).End(xlUp).Row を使います。
  • どの列にも空白がありうる表は、ws.Cells.Find("*", ..., SearchDirection:=xlPrevious) でシート全体を後ろから探します。
  • 行番号は Long 型で受けます。 Integer は 32,767 までなので、それより下の行でオーバーフロー(エラー 6)になります。
  • 見出しだけの表は「0件」として扱う分岐を入れます。 End(xlUp) は見出し行の番号を返すので、そのまま使うと見出しをデータとして読んでしまいます。
  • UsedRange は「使用済み範囲」の最後です。塗りつぶしだけのセルも含むので、値がある最後の行とは一致しないことがあります。

7方式の早見表

方式 書き方(最終行) 何を最後とみなすか 向いている表
End(xlUp) ws.Cells(ws.Rows.Count, 1).End(xlUp).Row 指定した列を一番下から上へたどって最初に当たるセル 必ず埋まる列がある表
End(xlDown) ws.Range("A1").End(xlDown).Row 指定したセルから下へたどって、連続したデータが切れる手前 途中に空白がない列
UsedRange ws.UsedRange.Row + ws.UsedRange.Rows.Count - 1 シートの使用済み範囲の最後の行 書式も含めた範囲を知りたいとき
CurrentRegion ws.Range("A1").CurrentRegion の最後の行 空白行と空白列で囲まれた範囲の最後の行 空白行で区切られた表の1つ分
Find ws.Cells.Find("*", SearchDirection:=xlPrevious).Row シート全体で、後ろから探して最初に見つかるセル どの列にも空白がありうる表
SpecialCells ws.Cells.SpecialCells(xlCellTypeLastCell).Row 使用済み範囲の最後のセル UsedRange と同じ使いどころ
ListObject lo.HeaderRowRange.Row + lo.ListRows.Count テーブルのデータ行の最後 テーブルとして書式設定した表

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「VBAの最終行取得|End・UsedRange・Findの違い早見表」

条件別:どの行を返すかの早見表

次の表をシートに作り、条件を1つずつ変えて各方式の結果を調べました。

A B C
1 No 品名 備考
2 1 品1 メモ
3 2 品2
4 3 (空白)
5 4 品4
6 5 品5

A列はすべて埋まり、B列は4行目が空白、C列は2行目だけに値があります。

条件 End(xlUp) A列 End(xlUp) B列 End(xlDown) A1から End(xlDown) B1から UsedRange CurrentRegion Find
上の表のまま(B4 が空白) 6 6 6 3 6 6 6
4行目を丸ごと空白にし、7行目までデータを入れる 7 7 3 3 7 3 7
5〜6行目を非表示にする 4 3 4 3 6 6 解除してから使う
フィルターで5〜6行目が隠れている 4 3 4 3 6 6 解除してから使う
10行目に塗りつぶしだけを設定する 6 6 6 3 10 6 6
A7:A9 に空文字を返す数式を入れる 9 6 9 3 9 9 9
見出しだけ(データ0件) 1 1 1048576 1048576 1 1 1
何も入っていないシート 1 1 1048576 1048576 1 1 Nothing
A7 に値を入れて A7:A8 を結合する 7 7 7 3 7 7 7
  • 数字は、確認環境に書いた VBA 互換モードで動かして得た行番号です。CurrentRegion は A1 を起点にし、Find は LookIn:=xlFormulas で検索しています。
  • 手元の Excel で同じ表を出すには、後半の「確認用マクロ」をそのまま貼って動かします。 自分のブックの表で試すと、どの方式が合うかをすぐに見比べられます。
  • 非表示行とフィルター中の Find は、リファレンスに隠れたセルの扱いが書かれていないため、表には入れていません。絞り込みや非表示を解除してから取得する形にすると、方式によらず同じ行が得られます(書き方は後述)。

表から読み取れること

条件 気をつける方式 理由
列の途中に空白がある End(xlDown) 空白の手前(3行目)で止まる
空白行で表が分かれている End(xlDown)、CurrentRegion 最初のかたまりの最後(3行目)を返す
非表示行・フィルター中 End(xlUp)、End(xlDown) 見えている行の中での最後(4行目、3行目)を返した
書式だけのセルがある UsedRange 書式だけの行(10行目)まで含む
空文字を返す数式がある End(xlUp)、UsedRange、CurrentRegion、Find 数式が入った行(9行目)を返す
データ0件 End(xlDown) シートの最終行(1048576)まで進む
一番下が結合セル End(xlUp) ほか 結合範囲の先頭の行(7行目)を返す

SpecialCells(xlCellTypeLastCell) と ListObject の位置づけ

この2つは、リファレンスの記載をもとに整理します。

方式 リファレンス・サポートの記載 読み取れること
SpecialCells(xlCellTypeLastCell) Range.SpecialCells の例に「Sheet1 の使用済み範囲の最後のセルを選択する」とある。Microsoft サポートには、空のセルに書式があると、最後のセルがデータのある範囲の外になることがあると書かれている 使用済み範囲の右下のセルを指す。書式だけのセルも含まれる
ListObject.Range テーブルが適用されている範囲を返す 見出し・データ(集計行を表示していれば集計行)を含むテーブル全体
ListObject.DataBodyRange 見出し行を除いた値の範囲を返す データ部分だけ
ListObject.HeaderRowRange 見出し行の範囲を返す 見出しの行番号が分かる
ListObject.ListRows.Count テーブルの行(ListRow)の数を返す データの件数が分かる。0 ならデータ0件

End(xlUp):必ず埋まる列がある表の定番

Range.End は、リファレンスで「元の範囲を含む領域の端のセルを返す。End+方向キーを押すのと同じ」と説明されています。シートの一番下のセルから上向きにたどるのが、最終行取得の定番の形です。

Sub SampleEndUp()
    Dim ws As Worksheet
    Dim lastRow As Long

    Set ws = ThisWorkbook.Worksheets("Sheet1")
    lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row

    Debug.Print lastRow
End Sub
部分 意味
ws.Rows.Count シートの行数(1048576)。Excel の仕様では 1,048,576 行 × 16,384 列
ws.Cells(ws.Rows.Count, 1) A列の一番下のセル
.End(xlUp) そこから上へたどって最初に当たるセル
.Row そのセルの行番号

Cells と Rows.Count の両方にシートを付けます。 ws.Cells(Rows.Count, 1) のように片方だけにすると、Rows.Count はその時点で前面にあるシートを見にいきます。両方に ws. を付けておくと、どのシートが前面にあっても同じ結果になります。

End(xlUp) は指定した列だけを見ます。早見表の「B列」のとおり、最後の行のB列が空白だと、B列で取った最終行は表の最終行より小さくなります。基準にする列は、No や ID のように必ず埋まる列を選びます。

End(xlDown):連続したデータの切れ目まで

lastRow = ws.Range("A1").End(xlDown).Row

上から下へたどるので、途中に空白があるとそこで止まります。 早見表では、B列(4行目が空白)で 3 を返しました。また、見出しだけの表では下にデータがないため、シートの最終行(1048576)まで進みます。

End(xlDown) が合うのは、「空白が出るまでのひとかたまり」を取りたい場面です。表全体の最終行には End(xlUp) が向いています。

UsedRange・SpecialCells:使用済み範囲の最後

Worksheet.UsedRange は、シートの使用済み範囲を表す Range を返します。使用済み範囲が1行目から始まるとは限らないので、開始行に行数を足して 1 を引きます。

lastRow = ws.UsedRange.Row + ws.UsedRange.Rows.Count - 1
lastCol = ws.UsedRange.Column + ws.UsedRange.Columns.Count - 1

ws.UsedRange.Rows.Count だけだと「使用済み範囲の行数」なので、表が3行目から始まるシートでは最終行より 2 少ない値になります。

早見表のとおり、10行目に塗りつぶしだけを設定すると UsedRange の最終行は 10 になりました。値がある最後の行(6)とは別のものです。Microsoft サポートのページでは、不要な書式が残った範囲を消す手順として、データより先の行や列を選んで[すべてクリア]を行い、ブックを保存する方法が案内されています。

CurrentRegion:空白行・空白列で囲まれた表

Range.CurrentRegion は、リファレンスで「空白行と空白列の任意の組み合わせで囲まれた範囲」と説明されています。

Dim tbl As Range
Set tbl = ws.Range("A1").CurrentRegion
lastRow = tbl.Row + tbl.Rows.Count - 1
lastCol = tbl.Column + tbl.Columns.Count - 1
  • 列の途中に空白セルがあっても、その行のほかの列に値があれば、表はつながったものとして扱われます(早見表1行目:B4 が空白でも 6)。
  • 丸ごと空白の行があると、そこで表が切れます(早見表2行目:3)。
  • リファレンスには、保護されたワークシートではこのプロパティを使えないと書かれています。

1枚のシートに、空白行で区切って複数の表を置いているときに、表1つ分の範囲を取る用途に合います。

Find:どの列にも空白がありうる表

Find でワイルドカード * をシートの後ろから探すと、列を決めずに「何か入っている最後のセル」が見つかります。

Sub SampleFind()
    Dim ws As Worksheet
    Dim c As Range
    Dim lastRow As Long

    Set ws = ThisWorkbook.Worksheets("Sheet1")
    Set c = ws.Cells.Find(What:="*", After:=ws.Range("A1"), LookIn:=xlFormulas, _
                          LookAt:=xlPart, SearchOrder:=xlByRows, _
                          SearchDirection:=xlPrevious)
    If c Is Nothing Then
        lastRow = 0
    Else
        lastRow = c.Row
    End If

    Debug.Print lastRow
End Sub
引数 指定 理由
What "*" 何か入っているセルを探す
After ws.Range("A1") 検索は After の次のセルから始まる。逆方向なので、A1 の手前、つまりシートの末尾から探しはじめる
LookIn xlFormulas 数式が入ったセルも対象にする
LookAt xlPart 部分一致
SearchOrder xlByRows(最終行)/xlByColumns(最終列) 行の順に探すか、列の順に探すか
SearchDirection xlPrevious 後ろから前へ

リファレンスには、次の2点が書かれています。

  • 見つからないときは Nothing を返す。 何も入っていないシートでは Nothing になるので、.Row を付ける前に Is Nothing で分岐します。
  • LookIn・LookAt・SearchOrder・MatchByte の設定は保存され、次回省略すると前回の値が使われる。 毎回すべて書いておくと、直前の検索に左右されません。

最終列の取得

最終列は、行と列を入れ替えた形で書けます。

方式 書き方 結果(サンプル表)
End(xlToLeft) ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column 3
Find SearchOrder を xlByColumns にして .Column を取る 3
UsedRange ws.UsedRange.Column + ws.UsedRange.Columns.Count - 1 3

End(xlToLeft) は、見出し行(1行目)で取るのが定番です。 データ行には空白の列があっても、見出しはすべての列に入っていることが多いためです。見出しがない表や、行ごとに列数が違う表は Find を使います。

コピペ用:最終行・最終列の関数

標準モジュールに貼って使える4つの関数です。どれも Long 型で返し、シートを引数で受け取り、データがないときは 0 を返します。

Option Explicit

' 値がある最後の行(指定した列)。見出しだけ・空のシートは 0 を返す
Public Function LastRowInCol(ByVal ws As Worksheet, ByVal col As Long, _
                             Optional ByVal headerRow As Long = 1) As Long
    Dim r As Long
    r = ws.Cells(ws.Rows.Count, col).End(xlUp).Row
    If r <= headerRow Then
        LastRowInCol = 0
    Else
        LastRowInCol = r
    End If
End Function

' 値がある最後の行(シート全体)。どの列に空白があってもよい
Public Function LastRowInSheet(ByVal ws As Worksheet, _
                               Optional ByVal headerRow As Long = 1) As Long
    Dim c As Range
    Set c = ws.Cells.Find(What:="*", After:=ws.Range("A1"), LookIn:=xlFormulas, _
                          LookAt:=xlPart, SearchOrder:=xlByRows, _
                          SearchDirection:=xlPrevious)
    If c Is Nothing Then
        LastRowInSheet = 0
    ElseIf c.Row <= headerRow Then
        LastRowInSheet = 0
    Else
        LastRowInSheet = c.Row
    End If
End Function

' 値がある最後の列(指定した行)。その行が空なら 0 を返す
Public Function LastColInRow(ByVal ws As Worksheet, ByVal r As Long) As Long
    Dim c As Long
    c = ws.Cells(r, ws.Columns.Count).End(xlToLeft).Column
    If c = 1 And IsEmpty(ws.Cells(r, 1).Value) Then
        LastColInRow = 0
    Else
        LastColInRow = c
    End If
End Function

' 値がある最後の列(シート全体)。空のシートは 0 を返す
Public Function LastColInSheet(ByVal ws As Worksheet) As Long
    Dim c As Range
    Set c = ws.Cells.Find(What:="*", After:=ws.Range("A1"), LookIn:=xlFormulas, _
                          LookAt:=xlPart, SearchOrder:=xlByColumns, _
                          SearchDirection:=xlPrevious)
    If c Is Nothing Then
        LastColInSheet = 0
    Else
        LastColInSheet = c.Column
    End If
End Function

シートの状態を変えながら呼び出した結果です。

シートの状態 LastRowInCol(ws, 1) LastRowInSheet(ws) LastColInRow(ws, 1) LastColInSheet(ws)
何も入っていない 0 0 0 0
見出し(A1:C1)だけ 0 0 3 3
A列は6行目まで、B列は5行目まで、C列は見出しだけ、E3 に値 6 6 3 5

3つ目の状態では、LastRowInCol(ws, 2) が 5、LastRowInCol(ws, 3) が 0、LastColInRow(ws, 3) が 5、LastColInRow(ws, 9) が 0 でした。列や行を指定する関数は、その列・その行だけを見ていることが分かります。

使い方:0件を分岐し、次の行に書く

Sub AppendSample()
    Dim ws As Worksheet, n As Long
    Set ws = ThisWorkbook.Worksheets("Sheet1")
    n = LastRowInCol(ws, 1)
    If n = 0 Then n = 1          ' 見出しだけのときは見出しの次の行から書く
    ws.Cells(n + 1, 1).Value = "追加"
End Sub

見出しだけのシートで動かすと A2 に、6行目までデータがあるシートで動かすと A7 に「追加」と入りました。

データを読む側では、0 のときに処理を抜けます。

n = LastRowInCol(ws, 1)
If n = 0 Then
    MsgBox "データがありません"
    Exit Sub
End If
For i = 2 To n
    ' 1行ずつの処理
Next

0件の分岐がないと、For i = 2 To 1 となってループは回りませんが、ws.Range("A2:A" & n) のように範囲を組み立てる書き方では、A2:A1 という見出しを含む範囲になります。0件を先に分けておくと、どちらの書き方でも同じ動きになります。

Integerで受けるとオーバーフローする例

A列の 40000 行目に値があるシートで、最終行を Integer と Long で受けて比べました。

Function OverflowSample() As String
    Dim ws As Worksheet, n As Integer, m As Long
    On Error GoTo EH
    Set ws = ThisWorkbook.Worksheets(1)
    ws.Cells(40000, 1).Value = "x"
    m = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
    OverflowSample = "Long: " & m & vbLf
    n = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
    OverflowSample = OverflowSample & "Integer: " & n & vbLf
    Exit Function
EH:
    OverflowSample = OverflowSample & "Integer: エラー " & Err.Number & vbLf
End Function

結果:

Long: 40000
Integer: エラー 6
型 範囲(リファレンスの記載) 行番号を受けられるか
Integer -32,768 〜 32,767 32,767 行目まで
Long -2,147,483,648 〜 2,147,483,647 シートの最終行(1,048,576)まで入る

エラー 6 は、リファレンスで「代入先の制限を超える代入をしようとしたときに起きる」と説明され、対処として「より広い範囲の値を持てる型の変数に代入する」が挙げられています。行番号・列番号・ループのカウンターは Long で宣言しておくと、データが増えても同じコードで動きます。

値がある最後の行と、使用済み範囲の最後の行

「最終行」という言葉は、次の3つのどれを指すかで使う方式が変わります。

指すもの 説明 取り方
値か数式がある最後の行 空文字を返す数式の行も含む End(xlUp)、Find
表示される値がある最後の行 空文字を返す数式の行は含めない End(xlUp) のあと、値が空の行を上へ戻る
使用済み範囲の最後の行 書式だけの行も含む UsedRange、SpecialCells(xlCellTypeLastCell)

空文字を返す数式を飛ばす

A7:A9 に =IF(B7="","",B7) を入れると、見た目は空でもセルには数式があります。表示される値がある最後の行を取りたいときは、End(xlUp) の結果から上へ戻ります。

' 空文字を返す数式を飛ばして、表示される値がある最後の行を返す
Public Function LastValueRowInCol(ByVal ws As Worksheet, ByVal col As Long, _
                                  Optional ByVal headerRow As Long = 1) As Long
    Dim r As Long
    r = ws.Cells(ws.Rows.Count, col).End(xlUp).Row
    Do While r > headerRow
        If Len(CStr(ws.Cells(r, col).Value)) > 0 Then Exit Do
        r = r - 1
    Loop
    If r <= headerRow Then
        LastValueRowInCol = 0
    Else
        LastValueRowInCol = r
    End If
End Function

A7:A9 に上の数式を入れた状態で、LastRowInCol(ws, 1) は 9、LastValueRowInCol(ws, 1) は 6 でした。

一番下が結合セルのとき

結合セルの値は先頭のセルに入るので、End(xlUp) は結合範囲の先頭の行を返します。Range.MergeArea は、指定したセルを含む結合範囲を返すプロパティです(結合されていなければ、そのセル自身を返します)。これで結合範囲の最後の行を求めます。

' 一番下が結合セルでも、結合範囲の最後の行を返す
Public Function LastRowWithMerge(ByVal ws As Worksheet, ByVal col As Long, _
                                 Optional ByVal headerRow As Long = 1) As Long
    Dim c As Range, r As Long
    Set c = ws.Cells(ws.Rows.Count, col).End(xlUp)
    r = c.MergeArea.Row + c.MergeArea.Rows.Count - 1
    If r <= headerRow Then
        LastRowWithMerge = 0
    Else
        LastRowWithMerge = r
    End If
End Function

A7:A8 を結合した状態で、LastRowInCol(ws, 1) は 7、LastRowWithMerge(ws, 1) は 8 でした。

非表示行・フィルター中のシートで取得する

早見表では、非表示行やフィルターで隠れた行があると、End(xlUp) は見えている行の中での最後を返しました。隠れた行も含めた最終行がほしいときは、次のどちらかにします。

やり方 書き方 使うプロパティ・メソッド
フィルターを解除してから取る If ws.FilterMode Then ws.ShowAllData FilterMode(フィルターモードなら True)、ShowAllData(絞り込まれたリストのすべての行を表示する)
フィルターの範囲から求める ws.AutoFilter.Range の最後の行 AutoFilter.Range(オートフィルターが適用されている範囲)
Sub LastRowOnFilteredSheet()
    Dim ws As Worksheet, lastRow As Long

    Set ws = ThisWorkbook.Worksheets("Sheet1")
    If ws.FilterMode Then ws.ShowAllData
    lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row

    Debug.Print lastRow
End Sub

FilterMode、ShowAllData、AutoFilter.Range は、Microsoft Learn のリファレンスに載っている定義に沿って書いています。早見表のとおり、UsedRange と CurrentRegion は、隠れた行があっても 6 を返しました。

テーブル(ListObject)の最終行

[テーブルとして書式設定]した表は、ListObject から行数を取れます。列を決めたり、空白を気にしたりせずに済みます。

' テーブルのデータの最後の行。データ0件なら 0 を返す
Public Function LastRowOfTable(ByVal lo As ListObject) As Long
    If lo.ListRows.Count = 0 Then
        LastRowOfTable = 0
    Else
        LastRowOfTable = lo.HeaderRowRange.Row + lo.ListRows.Count
    End If
End Function

Sub SampleTable()
    Dim lo As ListObject
    Set lo = ThisWorkbook.Worksheets("Sheet1").ListObjects(1)

    Debug.Print lo.ListRows.Count          ' データの件数
    Debug.Print LastRowOfTable(lo)         ' データの最後の行
End Sub

ListObjects、ListRows.Count、HeaderRowRange、DataBodyRange は、Microsoft Learn のリファレンスに載っている定義に沿って書いています。見出し行を表示しているテーブルを前提にした式です。行を追加するときは、リファレンスの例にある lo.ListRows.Add で末尾に1行増やせます。

確認用マクロ:手元のブックで5方式を見比べる

自分の表でどの方式が何行目を返すかを、一度に出すマクロです。

' 5方式の結果を1行ずつ文字列にまとめる
Public Function LastRowReport(ByVal ws As Worksheet, ByVal col As Long) As String
    Dim s As String, c As Range
    s = "End(xlUp)     : " & ws.Cells(ws.Rows.Count, col).End(xlUp).Row & vbCrLf
    s = s & "End(xlDown)   : " & ws.Cells(1, col).End(xlDown).Row & vbCrLf
    s = s & "UsedRange     : " & ws.UsedRange.Row + ws.UsedRange.Rows.Count - 1 & vbCrLf
    s = s & "CurrentRegion : " & ws.Range("A1").CurrentRegion.Row + _
            ws.Range("A1").CurrentRegion.Rows.Count - 1 & vbCrLf
    Set c = ws.Cells.Find(What:="*", After:=ws.Range("A1"), LookIn:=xlFormulas, _
                          LookAt:=xlPart, SearchOrder:=xlByRows, _
                          SearchDirection:=xlPrevious)
    If c Is Nothing Then
        s = s & "Find          : Nothing"
    Else
        s = s & "Find          : " & c.Row
    End If
    LastRowReport = s
End Function

Public Sub ShowLastRowReport()
    Debug.Print LastRowReport(ActiveSheet, 1)
End Sub

サンプル表で LastRowReport(ws, 2)(B列を指定)を呼んだ結果です。

End(xlUp)     : 6
End(xlDown)   : 3
UsedRange     : 6
CurrentRegion : 6
Find          : 6

ShowLastRowReport は、この文字列を Debug.Print でイミディエイト ウィンドウに出すだけの入口です。

どの方式を選ぶかの判断表

表の状態・目的 選ぶ方式
No や ID など、必ず埋まる列がある End(xlUp)(その列で)
どの列にも空白がありうる Find(後ろから検索)
テーブルとして書式設定している ListObject(ListRows.Count)
空白行で区切った表の1つ分を取りたい CurrentRegion
空白が出るまでのひとかたまりを取りたい End(xlDown)
書式も含めて、使われている範囲を知りたい UsedRange、SpecialCells(xlCellTypeLastCell)
空文字を返す数式が下まで入っている End(xlUp) のあと、値が空の行を上へ戻る
フィルター中・非表示行がある 解除してから End(xlUp)、または UsedRange

確かめて分かったこと

  • End(xlUp) は列ごとに結果が違いました。 同じ表でも、A列は 6、C列(2行目だけ値がある)は 2 です。基準の列の選び方で結果が決まります。
  • 見出しだけの表では、End(xlUp) が 1、End(xlDown) が 1048576 を返しました。 どちらも「データの最終行」ではないので、0件の分岐が要ります。
  • 何も入っていないシートでも、UsedRange は A1(1行目)を返しました。 行数 0 にはならないので、UsedRange だけでは空のシートを見分けられません。Find は Nothing を返すので見分けられます。
  • 塗りつぶしだけの行で変わったのは UsedRange だけでした。 End・CurrentRegion・Find は 6 のままです。
  • 空文字を返す数式は、End(xlUp)・UsedRange・CurrentRegion・Find のどれでも「入っている行」として数えられました。
  • 非表示行があると、End(xlUp) と End(xlDown) は見えている行で止まりました。 UsedRange と CurrentRegion は隠れた行も含めた 6 を返しました。

よくある質問

Q. End(xlUp) と End(xlDown) の違いは? A. たどる向きが違います。End(xlUp) はシートの一番下から上へたどるので途中の空白に左右されず、End(xlDown) は上から下へたどるので最初の空白の手前で止まります。表全体の最終行には End(xlUp) が向いています。

Q. UsedRange と CurrentRegion の違いは? A. UsedRange はシート全体の使用済み範囲、CurrentRegion は指定したセルを含む、空白行と空白列で囲まれた範囲です。UsedRange はワークシートのプロパティ、CurrentRegion は Range のプロパティです。

Q. 最終行が実際より大きくなるときは? A. 空文字を返す数式か、書式だけのセルが下にあることが多いです。End(xlUp) や Find は数式のある行を、UsedRange は書式だけの行も数えます。数式を飛ばすには、値が空の行を上へ戻る LastValueRowInCol の形にします。

Q. 空白がある列で最終行を取得するには? A. 必ず埋まる別の列で End(xlUp) を使うか、Find でシート全体を後ろから検索します。Find は列を決めずに探すので、どの列に空白があっても表の最終行が取れます。

Q. 最終行の変数は Integer でもよいですか? A. Long にします。Integer は 32,767 までで、それより下の行番号を代入するとエラー 6(オーバーフロー)になります。

まとめ

  • 必ず埋まる列があるなら End(xlUp)、どの列にも空白がありうるなら Find を使います。
  • Cells と Rows.Count の両方にシートを付けると、前面のシートに左右されません。
  • 行番号は Long で受けます。 Integer は 32,767 行目までです。
  • 見出しだけ・空のシートは 0 件として分岐します。End(xlUp) は見出し行を、End(xlDown) はシートの最終行を返します。
  • UsedRange と SpecialCells(xlCellTypeLastCell) は使用済み範囲の最後で、書式だけのセルも含みます。
  • 空文字を返す数式、結合セル、非表示行は、それぞれ「上へ戻る」「MergeArea で広げる」「解除してから取る」で対応できます。
  • テーブルは ListRows.Count で件数が取れ、列や空白を気にせずに済みます。

参考・出典

  • Microsoft Learn「Range.End property (Excel)」 https://learn.microsoft.com/en-us/office/vba/api/excel.range.end
  • Microsoft Learn「Worksheet.UsedRange property (Excel)」 https://learn.microsoft.com/en-us/office/vba/api/excel.worksheet.usedrange
  • Microsoft Learn「Range.CurrentRegion property (Excel)」 https://learn.microsoft.com/en-us/office/vba/api/excel.range.currentregion
  • Microsoft Learn「Range.Find method (Excel)」 https://learn.microsoft.com/en-us/office/vba/api/excel.range.find
  • Microsoft Learn「Range.SpecialCells method (Excel)」 https://learn.microsoft.com/en-us/office/vba/api/excel.range.specialcells
  • Microsoft Learn「Range.MergeArea property (Excel)」 https://learn.microsoft.com/en-us/office/vba/api/excel.range.mergearea
  • Microsoft Learn「ListObject object (Excel)」 https://learn.microsoft.com/en-us/office/vba/api/excel.listobject
  • Microsoft Learn「ListRows object (Excel)」 https://learn.microsoft.com/en-us/office/vba/api/excel.listrows
  • Microsoft Learn「Worksheet.FilterMode property (Excel)」 https://learn.microsoft.com/en-us/office/vba/api/excel.worksheet.filtermode
  • Microsoft Learn「Worksheet.ShowAllData method (Excel)」 https://learn.microsoft.com/en-us/office/vba/api/excel.worksheet.showalldata
  • Microsoft Learn「AutoFilter.Range property (Excel)」 https://learn.microsoft.com/en-us/office/vba/api/excel.autofilter.range
  • Microsoft Learn「Integer data type」 https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/integer-data-type
  • Microsoft Learn「Long data type」 https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/long-data-type
  • Microsoft Learn「Overflow (Error 6)」 https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/overflow-error-6
  • Microsoft サポート「Locate and reset the last cell on a worksheet」 https://support.microsoft.com/en-us/office/locate-and-reset-the-last-cell-on-a-worksheet-c9e468a8-0fc3-4f69-8038-b3c1d86e99e9
  • Microsoft サポート「Excel specifications and limits」 https://support.microsoft.com/en-us/office/excel-specifications-and-limits-1672b34d-7043-467e-8e27-269d656771c3

(いずれも 2026-10-06 に確認)

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「VBAの最終行取得|End・UsedRange・Findの違い早見表」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?