【作成中】【Excel VBA】データが入力されている最後の行番号を取得する

データが入力されている最後の行番号を知りたい場面はいくつかある。最後の行まで順番にデータを参照したり、最後の行の次の行から新たにデータを入力する場合などがある。

最後の行を取得する方法にもいくつかある。

目次

Excel VBAでデータが入力されている最後の行番号を取得する方法【全パターン整理】

「最後の行」を取る方法は1つではありません。
どの列を見るのか、空白が混ざるのか、結合セルがあるのか、数式だけ入っているのか等で最適解が変わります。

この記事では、VBAで使われる手法を カテゴリ別に全網羅 します。


前提:どの「最後」を取りたいか?

最後の行番号には主に3種類あります。

  • 列ベース:特定の列で、データがある最後の行(最も一般的)
  • シート全体ベース:シートで使われている最後の行(UsedRangeなど)
  • 範囲ベース:表(CurrentRegion / テーブル / 指定範囲)内の最後の行

1. Cells(Rows.Count, 列).End(xlUp)(最定番・最実務)

特定列の最終行(空白が途中にあっても、下端から上に見つける)。

Dim lastRow As Long
lastRow = Cells(Rows.Count, "A").End(xlUp).Row

列番号でもOK。

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

注意点

  • 対象列の下の方に「ゴミ(スペース、書式だけ等)」があるとズレることがあります。

Cells(Rows.Count, 列).End(xlUp) の意味を詳しく解説【最後の行取得の定番】

Excel VBAで「データが入っている最後の行」を取るとき、最も定番なのが次の書き方です。

Dim lastRow As Long
lastRow = Cells(Rows.Count, "A").End(xlUp).Row

この1行でやっていることは、ざっくり言うと次の通りです。

「A列の一番下(最終行)から上方向に、最初に見つかるデータセルまでジャンプして、その行番号を返す」


1. まずは式を分解して読む

このコードは3段階に分解すると理解しやすいです。

Cells(Rows.Count, "A")   'A列の最終行のセル(例:A1048576)を指定
    .End(xlUp)           'そこから上へCtrl+↑と同じ動作でジャンプ
    .Row                 'ジャンプ先セルの行番号を取り出す

2. Cells(Rows.Count, "A") の意味

Cells(行番号, 列) は「座標でセルを指定」

Cells(1, 1)   'A1
Cells(2, 1)   'A2

ここで使っている Rows.Countそのシートで使える最大行数を返します。

  • Excel 2007以降の通常シートなら 1,048,576 行
  • したがって、
Cells(Rows.Count, "A")

はだいたい次の意味になります。

「A列の一番下のセル(A1048576)」

※列は "A" の代わりに 1 のような列番号でもOKです。

Cells(Rows.Count, 1) 'A列

3. .End(xlUp) の意味(Ctrl + ↑ と同じ)

.End(方向) は、Excelの操作で言うところの Ctrlキーを押しながら矢印キーで移動する動きです。

  • xlUp → Ctrl + ↑
  • xlDown → Ctrl + ↓
  • xlToLeft → Ctrl + ←
  • xlToRight → Ctrl + →

つまり

Cells(Rows.Count, "A").End(xlUp)

「A1048576 から Ctrl + ↑ した場所」

を返します。

どういう場所に止まるの?

基本的には「連続したデータの端」に止まります。

  • 下側が空白で、途中にデータがある → 最後のデータセルに止まる
  • 列が全部空白 → A1 に止まる(ここが落とし穴)

4. .Row の意味

.End(xlUp) の戻り値は Range(セル)オブジェクトです。
そのセルの行番号だけ取り出すのが .Row です。

Dim r As Range
Set r = Cells(Rows.Count, "A").End(xlUp)

Debug.Print r.Address  '例:$A$123
Debug.Print r.Row      '例:123

5. “列Aの最終行” を取るということ

この手法が「列Aの最終行」と言われる理由はここです。

Cells(Rows.Count, "A")

列Aの一番下を起点にしているため、
最後の行は「列Aを基準にした最後の行」になります。

例えば、

  • A列に必ずIDが入る設計 → この方法が最適
  • A列が空白で、B列にデータがある → 期待より小さい行になることがある

6. 落とし穴と対策

落とし穴①:列が完全に空だと「1」になる

A列が完全に空だと、End(xlUp) は A1 に止まります。

lastRow = Cells(Rows.Count, "A").End(xlUp).Row
'→ 1 になりやすい

対策(データなしなら0にする例)

Dim lastRow As Long
lastRow = Cells(Rows.Count, "A").End(xlUp).Row

If WorksheetFunction.CountA(Columns("A")) = 0 Then
    lastRow = 0
End If

落とし穴②:最終行の「データ」の定義が列依存

この方法は「指定した列」に依存します。
最終行判定に適した列(必ず埋まる列)を選ぶのがコツです。


落とし穴③:書式だけ・スペースでも“データ扱い”になり得る

セルにスペースだけ入っていたり、見えない文字があると最終行がズレます。
この場合は Find 方式や配列方式が安定します(別記事で詳解)。


7. 実務で安全な書き方(シート明示)

ActiveSheet依存を避けるならこう書くのが鉄板です。

Dim ws As Worksheet
Set ws = Worksheets("Sheet1")

Dim lastRow As Long
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row

まとめ

Cells(Rows.Count, "A").End(xlUp).Row は、

  1. A列の最下行セルを取って(A1048576)
  2. Ctrl + ↑ の動作で上へジャンプして
  3. 止まったセルの行番号を返す

という仕組みです。


次に「列Aが空白の可能性がある」「数式で空("")が返る」などの条件があるなら、
その条件に最適化した“最終行取得の決定版コード”も作れます。どんなデータ構造ですか?(例:ID列あり/空白あり/テーブル/CSVなど)


2. Range("A" & Rows.Count).End(xlUp)(1と同じ系統)

Dim lastRow As Long
lastRow = Range("A" & Rows.Count).End(xlUp).Row

3. Find(検索で最終セルを取る:値/数式/書式も条件指定可能)

「本当に最後に使われたセル」を柔軟に取りたいならFindが強いです。

値 or 数式が入っている最後の行

Dim lastRow As Long
Dim c As Range

Set c = Cells.Find(What:="*", LookIn:=xlFormulas, _
                   SearchOrder:=xlByRows, SearchDirection:=xlPrevious)

If Not c Is Nothing Then
    lastRow = c.Row
Else
    lastRow = 0
End If

値だけ(表示値ベース)に寄せる

Set c = Cells.Find(What:="*", LookIn:=xlValues, _
                   SearchOrder:=xlByRows, SearchDirection:=xlPrevious)

特定列だけでFindする

Set c = Columns("A").Find(What:="*", LookIn:=xlFormulas, _
                          SearchOrder:=xlByRows, SearchDirection:=xlPrevious)
If Not c Is Nothing Then lastRow = c.Row

4. UsedRange(シートの使用範囲ベース:速いがズレやすい)

Dim lastRow As Long
lastRow = ActiveSheet.UsedRange.Rows(ActiveSheet.UsedRange.Rows.Count).Row

注意点(超重要)

  • 以前入力して消したセル、書式だけ残ったセルがあると 大きめにズレる ことがあります。
  • “ユーザーが触った跡”も拾いがち。

5. CurrentRegion(「アクティブセル領域」の最後:表の塊ベース)

Dim lastRow As Long
lastRow = ActiveCell.CurrentRegion.Rows(ActiveCell.CurrentRegion.Rows.Count).Row

開始セルを明示する方が安全です。

Dim rg As Range
Set rg = Range("A1").CurrentRegion
lastRow = rg.Rows(rg.Rows.Count).Row

注意点

  • 空白行/空白列があると領域が分断されます。

6. テーブル(ListObject)ならこれが最強(表が構造化されている前提)

Dim lastRow As Long
With ActiveSheet.ListObjects("Table1")
    lastRow = .Range.Rows(.Range.Rows.Count).Row
End With

データ本体だけなら DataBodyRange。

Dim lastRow As Long
With ActiveSheet.ListObjects("Table1")
    If Not .DataBodyRange Is Nothing Then
        lastRow = .DataBodyRange.Rows(.DataBodyRange.Rows.Count).Row
    Else
        lastRow = .HeaderRowRange.Row 'データなし
    End If
End With

7. SpecialCells(定数/数式セルを拾う:条件で「最後」を決められる)

定数(手入力値)だけの最後の行

Dim lastRow As Long
Dim rg As Range

On Error Resume Next
Set rg = Cells.SpecialCells(xlCellTypeConstants)
On Error GoTo 0

If Not rg Is Nothing Then
    lastRow = rg.Areas(rg.Areas.Count).Rows(rg.Areas(rg.Areas.Count).Rows.Count).Row
Else
    lastRow = 0
End If

数式セルだけの最後の行

Dim lastRow As Long
Dim rg As Range

On Error Resume Next
Set rg = Cells.SpecialCells(xlCellTypeFormulas)
On Error GoTo 0

If Not rg Is Nothing Then
    lastRow = rg.Areas(rg.Areas.Count).Rows(rg.Areas(rg.Areas.Count).Rows.Count).Row
Else
    lastRow = 0
End If

注意点

  • 範囲が複数Areaになるので「最後のArea=最後」とは限らないことがある(扱いに注意)。

8. CountAで「非空セル数」から推定(連続データ限定)

A列が途中で空白にならない前提の場合

Dim lastRow As Long
lastRow = WorksheetFunction.CountA(Columns("A"))

注意点

  • 途中空白があると 最後の行ではなく件数 になります。

9. 配列に読み込んで判定(高速&柔軟:大量データ向け)

例:A列の最終行を「下から走査」

Dim lastRow As Long, i As Long
Dim v As Variant

v = Range("A1", Cells(Rows.Count, "A").End(xlUp)).Value

For i = UBound(v, 1) To 1 Step -1
    If Len(v(i, 1) & vbNullString) > 0 Then
        lastRow = i
        Exit For
    End If
Next

強み

  • 「空白」「スペース」「数式結果が空」など、判定条件を自由に書ける
  • 大量データでSelect/Endを多用するより安定しやすい

10. 最終セル(xlCellTypeLastCell)※非推奨(Excelが覚えている最後)

Dim lastRow As Long
lastRow = Cells.SpecialCells(xlCellTypeLastCell).Row

注意点(重要)

  • “昔使っていた”セルも残るためズレやすい
  • 仕様的に「最終行を取りたい」用途には不向き

どれを使うべき?(結論)

迷ったらこれ(列ベースの定番)

lastRow = Cells(Rows.Count, "A").End(xlUp).Row

シート全体の「本当に最後」を取りたい(値/数式含む)

Set c = Cells.Find(What:="*", LookIn:=xlFormulas, SearchOrder:=xlByRows, SearchDirection:=xlPrevious)
If Not c Is Nothing Then lastRow = c.Row

テーブル運用ならこれ

lastRow = ActiveSheet.ListObjects("Table1").Range.Rows.Count + ActiveSheet.ListObjects("Table1").Range.Row - 1

よくある落とし穴

  • 「書式だけ」入っているセルが下にある → End/UsedRangeがズレる
  • 数式が入っているが表示は空("") → LookIn設定で結果が変わる
  • 途中空白がある → CountAやCurrentRegionが期待通りにならない

必要なら、あなたのケース(例:A列にID、途中空白あり/数式あり/フィルタあり等)に合わせて、最も安全な1本に絞った実装例も出します。どの列・どんなデータ構造で「最後」を取りたいですか?

よかったらシェアしてね!
  • URLをコピーしました!
目次