Contents
この記事でわかること
VBAでデータの最終行・最終列を正確に取得する方法を4つ紹介し、比較表付きで使い分けを解説します。
- 対象:VBAでFor文やRange操作を始めたが、最終行の取得で困っている人
- 所要時間:コピペ → 実行まで3分
結論:迷ったらEnd(xlUp)を使えばOK
最終行の取得にはいくつか方法がありますが、迷ったら Cells(Rows.Count, 1).End(xlUp).Row を使えばほぼ間違いありません。
自分も最初は「lastRow = Cells(Rows.Count, 1).End(xlUp).Row」の意味がわからず、ネットで見つけたコードを意味もわからずコピペしていました。でも、途中に空白行があるデータで End(xlDown) を使ってしまい、最終行がズレて集計結果がおかしくなったことがあります。正直あれは焦りました。
この記事で4つの方法を整理してからは、データを見て「このデータならEnd(xlUp)」「空白が多いならFindが安全」とすぐ判断できるようになりました。同じように迷っている方の参考になればうれしいです。
最終行を取得する4つの方法
| # | 方法 | コード | 特徴 |
|---|---|---|---|
| 1 | End(xlUp) | Cells(Rows.Count, 1).End(xlUp).Row |
最も万能。下から上に検索 |
| 2 | UsedRange | ActiveSheet.UsedRange.Rows.Count |
シート全体の使用範囲 |
| 3 | SpecialCells | Cells.SpecialCells(xlCellTypeLastCell).Row |
Ctrl+End相当 |
| 4 | Range.Find | Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row |
値があるセルだけ検索 |
比較表:どの方法をどう使い分けるか
| 項目 | End(xlUp) | UsedRange | SpecialCells | Find |
|---|---|---|---|---|
| 精度(値のみ) | 高 | 中 | 中 | 高 |
| 空白行への耐性 | 強い | 弱い | 弱い | 強い |
| 書式のみセルの扱い | 無視する | 含む | 含む | 無視する |
| 列の指定 | できる | できない | できない | できる |
| 空シートでの動作 | 1を返す | エラーなし | エラー | エラー |
| コードの短さ | 短い | 短い | 短い | やや長い |
| おすすめ度 | ★★★ | ★★ | ★ | ★★★ |
おすすめ: 普段使いは End(xlUp)。書式のみのセルを除外して正確に取りたい場合は Find。シート全体の範囲が必要な場合は UsedRange。
方法1:Cells.End(xlUp) — 最も万能
原理:シートの最下行(1048576行目)から上方向に検索し、最初にデータがあるセルの行番号を返します。Excelで Ctrl + ↑ を押すのと同じ動きです。
Sub 最終行を取得_EndXlUp()
Dim lastRow As Long
' A列の最終行を取得
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
MsgBox "A列の最終行: " & lastRow
End Sub
ポイント:
Rows.Countはシートの最大行数(1048576)を返しますEnd(xlUp)は「上方向に最初のデータがあるセル」に移動します- 列番号を変えれば、任意の列の最終行を取得できます(例:B列なら
Cells(Rows.Count, 2))
Sub 各列の最終行を取得()
Dim lastRowA As Long
Dim lastRowB As Long
Dim lastRowC As Long
' 列ごとに最終行を取得
lastRowA = Cells(Rows.Count, 1).End(xlUp).Row ' A列
lastRowB = Cells(Rows.Count, 2).End(xlUp).Row ' B列
lastRowC = Cells(Rows.Count, 3).End(xlUp).Row ' C列
MsgBox "A列: " & lastRowA & vbCrLf & _
"B列: " & lastRowB & vbCrLf & _
"C列: " & lastRowC
End Sub
注意: A列が空でも他の列にデータがある場合、A列の最終行は「1」になります。データがある列を指定してください。
方法2:UsedRange — シート全体の使用範囲
原理:シートの「使用済み範囲」を返します。一度でも何かを入力・書式設定したセルが含まれます。
Sub 最終行を取得_UsedRange()
Dim lastRow As Long
' UsedRangeの行数 + 開始行 - 1 = 最終行
With ActiveSheet.UsedRange
lastRow = .Rows(.Rows.Count).Row
End With
MsgBox "UsedRangeの最終行: " & lastRow
End Sub
ポイント:
UsedRange.Rows.Countだけでは正確な行番号にならない場合があります(1行目が空の場合).Rows(.Rows.Count).Rowで正確な行番号を取得します- 書式だけ設定したセル(値は空)も範囲に含まれるため、End(xlUp)より大きい値になることがあります
方法3:SpecialCells(xlCellTypeLastCell) — Ctrl+End相当
原理:Excelで Ctrl + End を押したときに移動するセルの行番号を返します。
Sub 最終行を取得_SpecialCells()
Dim lastRow As Long
' Ctrl+End相当の最終セル
lastRow = Cells.SpecialCells(xlCellTypeLastCell).Row
MsgBox "SpecialCellsの最終行: " & lastRow
End Sub
注意点:
- 行や列を削除した直後は、古い位置を返すことがあります(保存してから再実行すると正しくなる)
- 空のシートではエラーになります(エラー処理が必要)
- UsedRangeと同様、書式のみのセルも含みます
方法4:Range.Find — 値があるセルだけを正確に検索
原理:シート内を逆方向に検索し、値が入っている最後のセルを見つけます。書式のみのセルは完全に無視するため、最も正確です。
Sub 最終行を取得_Find()
Dim lastRow As Long
Dim rng As Range
' 値が入っている最後のセルを検索
Set rng = Cells.Find( _
What:="*", _
After:=Cells(1, 1), _
LookIn:=xlValues, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious)
If Not rng Is Nothing Then
lastRow = rng.Row
Else
lastRow = 0 ' データなし
End If
MsgBox "Findの最終行: " & lastRow
End Sub
ポイント:
What:="*"で任意の値を検索(ワイルドカード)SearchDirection:=xlPreviousで末尾から逆方向に検索- データが1件もない場合は
Nothingが返るため、If Not rng Is Nothingのチェックが必要 - 書式だけのセルを完全に無視するため、UsedRangeやSpecialCellsより正確
実務で使う:最終行を取得してFor文でループ
実際の業務では、最終行を取得してからFor文で処理することがほとんどです。自分もこのパターンを覚えてからは、どんなデータ一覧でもサッと処理できるようになりました。
Sub データ一覧を処理する()
Dim lastRow As Long
Dim i As Long
' A列の最終行を取得
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
' データなしチェック
If lastRow < 2 Then
MsgBox "データがありません。", vbExclamation
Exit Sub
End If
' 2行目(ヘッダーの次)から最終行までループ
For i = 2 To lastRow
' ここにデータごとの処理を書く
' 例:B列に「処理済み」と入力
Cells(i, 2).Value = "処理済み"
Next i
MsgBox lastRow - 1 & " 件のデータを処理しました。"
End Sub
最終「列」の取得方法
最終列も同じ考え方で取得できます。
Sub 最終列を取得()
Dim lastCol As Long
' 1行目の最終列を取得(End(xlToLeft))
lastCol = Cells(1, Columns.Count).End(xlToLeft).Column
MsgBox "1行目の最終列: " & lastCol & _
"(" & Split(Cells(1, lastCol).Address, "$")(1) & "列)"
End Sub
| 方向 | コード | 用途 |
|---|---|---|
| 最終行(下から上) | Cells(Rows.Count, 列).End(xlUp).Row |
データの最終行を取得 |
| 最終列(右から左) | Cells(行, Columns.Count).End(xlToLeft).Column |
データの最終列を取得 |
| 最初の空行(上から下) | Cells(開始行, 列).End(xlDown).Row + 1 |
次のデータ入力行を取得 |
注意:
End(xlDown)は途中に空白行があるとそこで止まります。最終行を取得する目的では End(xlUp) を使ってください。
落とし穴
| # | 症状 | 原因 | 対策 |
|---|---|---|---|
| 1 | 最終行が1048576になる | 指定した列が完全に空 | データがある列を指定する。またはデータの有無を事前チェック |
| 2 | 最終行が実際より大きい | UsedRange/SpecialCellsが書式のみセルを含む | End(xlUp)またはFindを使う。不要な書式はセルをクリア(Delete) |
| 3 | End(xlDown)で途中の行が返る | 途中に空白行がある | End(xlDown)ではなくEnd(xlUp)を使う(下からではなく上から検索) |
| 4 | SpecialCellsでエラーが出る | シートにデータが1件もない | On Error Resume Next でエラー処理するか、End(xlUp)を使う |
| 5 | 別シートの最終行が正しく取れない | Cells がアクティブシートを参照している |
ws.Cells(ws.Rows.Count, 1).End(xlUp).Row のようにシートを明示する |
自分も最初、3番の落とし穴にハマりました。End(xlDown)で最終行を取ったつもりが、途中に空白行があったデータで集計がズレて、上司に提出した資料が間違っていたことがあります。それ以来、必ずEnd(xlUp)を使うようにしています。
FAQ
Q1. End(xlUp)とEnd(xlDown)は何が違う?
End(xlUp)は「シートの最下行から上方向に検索」、End(xlDown)は「指定セルから下方向に検索」です。途中に空白行があるデータではEnd(xlDown)が途中で止まるため、最終行の取得にはEnd(xlUp)を使ってください。
Q2. 複数列にデータがあるとき、どの列を基準にすべき?
データの「主キー」にあたる列(通常はA列のID列や名前列)を基準にするのが安全です。すべての列で最終行が異なる場合は、WorksheetFunction.Max で最大値を取るか、Findメソッドを使ってください。
Q3. シートを指定して最終行を取得するには?
Cells の前にシートオブジェクトを付けます:
Dim ws As Worksheet
Set ws = Worksheets("Sheet2")
Dim lastRow As Long
lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
Q4. 最終行が正しく取れないときのデバッグ方法は?
MsgBox や Debug.Print で値を確認します。また、Excelで Ctrl + End を押すと、Excelが認識している最終セルが確認できます。UsedRangeがズレている場合は、不要な行・列を削除して保存すると修正されます。
Q5. ヘッダー行がある場合、ループの開始行はどうする?
ヘッダーが1行目にある場合、For文は For i = 2 To lastRow のように2行目から開始します。ヘッダーが複数行の場合は開始行を調整してください。
まとめ
この記事では、VBAでデータの最終行・最終列を取得する4つの方法を比較しました。
- 普段使い:
Cells(Rows.Count, 1).End(xlUp).Row— これだけ覚えればOK - 正確に取りたい:
Cells.Find("*", SearchDirection:=xlPrevious).Row - シート全体の範囲:
ActiveSheet.UsedRange
最終行を正確に取得できれば、For文でのループ処理、データ集計、別シートへの転記など、あらゆるVBA処理の基盤が固まります。
関連記事
- セルの値に応じて行を自動で色分けする方法 — 最終行まで色分けを適用するパターン
- 特定の文字を含むセルを検索してハイライトする方法 — Find/FindNextの応用
- 重複データを一括削除して一意のリストを作る方法 — 最終行を使ったデータ整理
- 複数シートに同じ処理を一括実行する方法 — シート別に最終行を取得して処理
- セルの転記を自動化する方法 — 最終行を使った転記先の自動判定
次にやりたくなること
- 空白行・空白セルを一括で削除する方法 — 最終行を正確にした後、空白行を削除してデータを整形したい場合に
- 配列を使ってVBAの処理速度を10倍にする方法 — 最終行まで大量データを処理するなら、配列を使うと劇的に速くなります

コメント