【この記事について】本記事は 2026年9月19日 時点で確認した内容です。対象環境:Windows 版 Excel(Microsoft 365 / Excel 2021・2019)の VBA(Visual Basic for Applications)。Mac 版・Web 版では画面の名称や一部の表示が異なります。コードはご自身のブックのコピーで試してください。コードの根拠は Microsoft 公式ドキュメントです。掲載している構文と各メソッド・プロパティの仕様は、Microsoft Learn の該当ページ(記事末尾に出典)に記載のある書き方にもとづいています。本記事の内容の利用は、ご自身の判断と責任でお願いします。
「データが毎日増えるので、マクロの『何行目まで』を毎回書き換えている」
「ネットで見た End(xlUp) をまねしたら、なぜか『1』が返ってきた」
「最終行を取る書き方がいくつも出てきて、どれを使えばいいのか分からない」
先に結論です。ふだんの表なら、最終行は ws.Cells(ws.Rows.Count, 1).End(xlUp).Row の1行で取れます。シートのいちばん下のセルから上へ向かって、最初にぶつかったデータの行番号を返す書き方で、Microsoft の公式ドキュメントのコード例にも同じ形が載っています。つまずくのは書き方そのものではなく、「どのシートの」「どの列で」「データが0件のとき」の3点を決めていないときです。
この記事では、最終行を取る代表的な5つの方法を早見表で比べたうえで、基本形の読み方と、よくある4つのつまずきを順に説明します。最後に「迷ったときの選び方」も置きました。コードはコピーしてそのまま貼れる形にしてあります。焦らず、上から順に見ていきましょう。
最終行を取る5つの方法(早見表)
最初に全体像です。どれが正解というより、表の形によって向き・不向きがあります。迷ったら、いちばん上の「方法1」から始めてください。
| 方法 | 書き方(要点) | 向いている表 | 気をつける点 |
|---|---|---|---|
| 方法1 End(xlUp) |
Cells(Rows.Count, 1).End(xlUp).Row |
ほとんどの表(まずはこれ) | 基準にした列の、最後のデータまでしか見ない |
| 方法2 Find |
Cells.Find(What:="*", …, SearchDirection:=xlPrevious) |
どの列が最後まで埋まっているか分からない表 | 何も見つからないと Nothing が返る。引数は毎回すべて書く |
| 方法3 UsedRange |
UsedRange.Row + UsedRange.Rows.Count - 1 |
シート全体の「使われた範囲」を知りたいとき | 見た目より下の行を返すことがある |
| 方法4 SpecialCells |
Cells.SpecialCells(xlCellTypeLastCell).Row |
方法3と同じく「使われた範囲」の端を知りたいとき | 方法3と同じ注意が要る |
| 方法5 CurrentRegion |
Range("A1").CurrentRegion |
空白行のないひとかたまりの表 | 空白行で止まる。保護されたシートでは使えない |
この記事の中心は方法1です。方法2〜5は「方法1では困る場面」の逃げ道として覚えておけば十分です。

方法1:基本形 End(xlUp) の1行を読み解く
まずはコード全体です。Sheet1 の A列について、最後にデータが入っている行を調べて表示します。
Sub 最終行を調べる()
Dim ws As Worksheet
Dim lastRow As Long
Set ws = Worksheets("Sheet1")
lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
MsgBox "A列の最終行は " & lastRow & " 行目です"
End Sub
肝心の1行を、左から分解するとこうなります。
| 部品 | 意味 |
|---|---|
ws.Rows.Count |
シートの行の数。つまりいちばん下の行の番号 |
ws.Cells(ws.Rows.Count, 1) |
いちばん下の行の、1列目(A列)のセル |
.End(xlUp) |
そこから上に向かって、データの端まで移動したセル |
.Row |
そのセルの行番号 |
End は、Microsoft の説明では「End キーを押してから上方向キーを押す操作と同等」とされています。手で試すなら、A列のいちばん下のセルを選んで End キー、続けて ↑ キーを押してみてください。止まったセルの行番号が、このコードの答えです。
よく使う形1:2行目から最終行まで、1行ずつ処理する
1行目が見出しの表なら、2行目から最終行までを順に回すのが定番です。
Dim i As Long
For i = 2 To lastRow
' ここに1行ぶんの処理を書く
' 例:ws.Cells(i, 3).Value で i 行目の C列を読む
Next i
データが何行に増えても、lastRow が毎回その時点の最終行を拾ってくれます。「何行目まで」を手で書き換える作業は、これで要らなくなります。
よく使う形2:最終行の「次の行」にデータを足す
追記したいときは、最終行に + 1 します。公式ドキュメントのコード例でも、別シートの次の空き行を End(xlUp).Row + 1 で求めています。
Dim nextRow As Long
nextRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row + 1
ws.Cells(nextRow, 1).Value = "新しいデータ"
End(xlUp) でつまずく4つのパターン
書き方は1行でも、前提を決めずに使うと、静かに間違った答えを返します。エラーで止まってくれないぶん、気づきにくいのがやっかいな点です。次の4つを確認してください。
つまずき1:シートを指定していない(別のシートの最終行が返る)
ネットでよく見るのは、次のような短い書き方です。
lastRow = Cells(Rows.Count, 1).End(xlUp).Row ' どのシートか書いていない
公式ドキュメントによると、Cells も Rows も、前にシートを書かなければ「アクティブシート(いま画面に出ているシート)」を指します。つまり、マクロを実行したときにたまたま別のシートを開いていると、そのシートの最終行が返ってきます。
対策は、この記事の基本形のように Set ws = Worksheets("Sheet1") でシートを決め、ws.Cells・ws.Rows と頭に ws. を付けることです。なお、Worksheets("Sheet1") のシート名が実際の名前と1文字でも違うと「実行時エラー9」で止まります。そのときは次の記事を見てください。

つまずき2:データが0件でも「1」が返る
End(xlUp) は、上へ向かって「データの端」まで移動します。A列が見出しだけ、あるいは完全に空っぽのときは、いちばん上の1行目まで上がって止まるので、答えは 1 になります。「データが1件ある」のか「0件」なのか、この数字だけでは区別がつきません。
見出しが1行目にある表なら、最終行が2より小さいときは「データなし」と扱って、処理を止めておくのが安全です。
If lastRow < 2 Then
MsgBox "データがありません。処理を中止します"
Exit Sub
End If
この確認を入れておかないと、0件の日に見出しの行を処理してしまったり、行数の計算が0やマイナスになってエラーで止まったりします。セル範囲の指定がおかしくなって止まる「実行時エラー1004」とも関係が深いので、気になる方はこちらも合わせてどうぞ。

つまずき3:基準にした列の下のほうが空いている
方法1が見ているのは、指定した1つの列だけです。たとえば A列が「備考」で、最後の数行に備考が無ければ、その行はまるごと数えられません。
対策は、必ず全行に値が入る列を基準にすることです。通し番号・日付・伝票番号のような列が向いています。A列以外を基準にするなら、ws.Cells(ws.Rows.Count, 1) の 1 を列の番号(B列なら2、C列なら3)に変えてください。「どの列も途中で途切れる可能性がある」表なら、後で紹介する方法2(Find)を使います。
つまずき4:行番号を Integer で受けている(3万行を超えると止まる)
変数の型にも注意が要ります。公式ドキュメントの「データ型の概要」によると、Integer 型が入れられるのは -32,768 〜 32,767 までです。これを超える行番号を Integer の変数に入れようとすると「オーバーフローしました(エラー6)」になります。
Dim lastRow As Integer ' 32,767行を超えると入りきらない
Dim lastRow As Long ' こちらを使う(約21億まで入る)
行番号を入れる変数は、最初から Long にしておくと覚えてしまいましょう。この記事のコードはすべて Long にしてあります。
上から探す End(xlDown) は、途中の空白で止まる
「上から下へ探せばいいのでは?」と考えて、次のように書く方もいます。
lastRow = ws.Range("A1").End(xlDown).Row ' 途中に空白があると、その手前で止まる
これは End キーを押してから ↓ キーを押す操作と同じ動きです。表の途中に1つでも空白のセルがあれば、その手前で止まってしまいます。
下から上へ探す End(xlUp) なら、途中の空白は関係ありません。最終行は「下から上へ」探すのが基本だと覚えておいてください。
方法2:Find で「どの列でもいいから最後の行」を探す
列ごとに埋まり方がバラバラで、基準にできる列がない表では、シート全体を後ろから検索する Find メソッドが使えます。公式ドキュメントの Worksheet.Cells のページには、同じ考え方で「最後の列」を求めるコード例が載っています。それを行向きにしたものが次のコードです。
Sub 最終行をFindで調べる()
Dim ws As Worksheet
Dim c As Range
Dim lastRow As Long
Set ws = 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
MsgBox "このシートには何も入っていません"
Exit Sub
End If
lastRow = c.Row
MsgBox "最終行は " & lastRow & " 行目です"
End Sub
引数の意味は次のとおりです。
What:="*":何か入っているセルを探すAfter:=ws.Range("A1"):A1 の「次」から探し始める。後ろ向きに探すので、実際にはシートの最後のほうから見ていくことになりますSearchOrder:=xlByRows:行を横方向に見てから、次の行へ移るSearchDirection:=xlPrevious:後ろ向きに探す
注意点は2つです。
- 見つからないと
Nothingが返る。空のシートでc.Rowをいきなり読むとエラーで止まるので、上のコードのようにIf c Is Nothing Thenで先に確かめます。 - 引数は毎回すべて書く。公式ドキュメントによると、LookIn・LookAt・SearchOrder などの設定は Find を使うたびに保存され、省略すると前回の値が使われます。しかも画面の[検索]ダイアログの設定とも共有されます。手作業で検索したあとにマクロの結果が変わる、ということが起きないように、省略せずに書くのが公式の推奨です。
方法3・4:UsedRange と SpecialCells は「見た目より下」を返すことがある
シートで「使われている範囲」を表すのが UsedRange、その範囲の最後のセルを返すのが SpecialCells(xlCellTypeLastCell) です。
' 方法3:UsedRange
With ws.UsedRange
lastRow = .Row + .Rows.Count - 1
End With
' 方法4:SpecialCells
lastRow = ws.Cells.SpecialCells(xlCellTypeLastCell).Row
方法3で .Row を足しているのは、使われている範囲が1行目から始まるとは限らないからです。Row は範囲の最初の行番号、Rows.Count は範囲の行数なので、「最初の行+行数−1」で最後の行番号になります。
どちらも手軽ですが、「データが入っている最後の行」とは一致しないことがあります。Excel が「使った」と覚えている範囲は、データを消したあとや、書式だけが残っているセルのぶんまで広がっていることがあるためです。Ctrl+End を押して、データのずっと下まで飛んでしまうシートは要注意です。そうしたシートはファイルが重くなる原因にもなるので、次の記事の「使われている範囲」の項目も参考にしてください。

「データの最終行」がほしいなら方法1か方法2、「シートのどこまでが使われた扱いになっているか」を知りたいときに方法3・4、と使い分けるのが無難です。
方法5:CurrentRegion は「ひとかたまりの表」専用
CurrentRegion は、指定したセルを含む「空白の行と空白の列で囲まれた範囲」を返します。表が1つのかたまりになっているなら、表の範囲ごと取れるので便利です。
Dim tbl As Range
Set tbl = ws.Range("A1").CurrentRegion
lastRow = tbl.Row + tbl.Rows.Count - 1
ただし、表の途中に空白行が1行でもあると、そこで範囲が切れます。また、公式ドキュメントには保護されたワークシートでは使うことができないと書かれています。シートの保護をかけて運用している表では、方法1か方法2を選んでください。
迷ったときは、この順で選ぶ
どれを使うか迷ったら、上から順に当てはめてください。
- 必ず全行が埋まる列がある → 方法1(
End(xlUp))。その列を基準にする - どの列も途中で途切れうる → 方法2(Find)。
Nothingの確認を忘れずに - 空白行のないひとかたまりの表で、範囲ごと扱いたい → 方法5(CurrentRegion)。保護シートでは使わない
- シートの「使われた範囲」を調べたい → 方法3・4。データの最終行の代わりには使わない
そして、どの方法でも次の3つは共通です。
- シートを
ws.で指定する(アクティブシート任せにしない) - 行番号の変数は Long にする
- データ0件のときの動きを決めておく(1が返る/Nothing が返る)
よくある質問(Q&A)
Q. 最終行ではなく「最終列」を取りたいときは?
A. 方法2の Find で、SearchOrder:=xlByColumns に変えて .Column を読みます。公式ドキュメントの Worksheet.Cells のページに、Cells.Find(What:="*", After:=Range("A1"), SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column という形のコード例があります。この記事の方法2と同じく、シートの指定・Nothing の確認・LookIn などの引数の明示を足して使ってください。
Q. xlUp と書いたら「変数が定義されていません」と出ました
A. まず綴りを確認してください。xlUp の x・l(小文字のエル)を、数字の1やアルファベットの I と打ち間違えていることがよくあります。Option Explicit を入れていると、定義されていない名前として止まります。止まり方の見分け方は、コンパイルエラーの記事にまとめています。

Q. 最終行は取れたのに、ループの途中で「型が一致しません」と出ます
A. 最終行の取り方ではなく、途中のセルの中身が原因のことが多いです。数値のつもりの列に文字や空白、エラー値が混ざっていると、計算の行で止まります。セルの中身の確かめ方は次の記事を見てください。

Q. 表の下に「合計」の行があります。最終行はどうなりますか
A. 方法1でも方法2でも、合計行が最終行として返ります。データ部分だけを処理したいなら、合計行を表から離れた場所に置くか、lastRow - 1 のように合計行のぶんを差し引いてください。どちらにするか決めたら、コードにコメントで書き残しておくと、あとで読み返したときに迷いません。
Q. どの方法がいちばん「正しい」のですか
A. 表の形によって変わるので、1つには決められません。ただ、最初の1本として覚えるなら方法1です。公式ドキュメントのコード例にも繰り返し出てくる形で、読み方も単純だからです。困る場面が出てきたら、この記事の「迷ったときは、この順で選ぶ」に戻ってきてください。
まとめ:最終行は「どのシート・どの列・0件のとき」を決めてから取る
- 基本は
ws.Cells(ws.Rows.Count, 1).End(xlUp).Row。下から上へ探すので、途中の空白に強い - シートは
ws.で指定。書かないとアクティブシートの最終行が返る - データ0件でも1が返る。見出しのある表なら「2未満はデータなし」で止める
- 基準の列は必ず全行が埋まる列。無ければ Find を使い、
Nothingを確かめる - 行番号の変数は Long。UsedRange・SpecialCells は「見た目より下」を返すことがある
「何行目まで」を毎回書き換えていた作業は、この1行で終わりにできます。最初はコードの意味が全部分からなくても大丈夫です。基本形をコピーして、End キーと ↑ キーで答え合わせをするところから始めてみてください。1つずつ確かめていけば、マクロは必ずあなたの味方になります。
次に読む




参考にした一次情報(2026年9月19日確認)
Range.End プロパティ (Excel)|Microsoft Learn
https://learn.microsoft.com/ja-jp/office/vba/api/excel.range.end
XlDirection 列挙型 (Excel)|Microsoft Learn
https://learn.microsoft.com/ja-jp/office/vba/api/excel.xldirection
Range.Row プロパティ (Excel)|Microsoft Learn
https://learn.microsoft.com/ja-jp/office/vba/api/excel.range.row
Range.Rows プロパティ (Excel)|Microsoft Learn
https://learn.microsoft.com/ja-jp/office/vba/api/excel.range.rows
Worksheet.Rows プロパティ (Excel)|Microsoft Learn
https://learn.microsoft.com/ja-jp/office/vba/api/excel.worksheet.rows
Worksheet.Cells プロパティ (Excel)|Microsoft Learn
https://learn.microsoft.com/ja-jp/office/vba/api/excel.worksheet.cells
Range.Find メソッド (Excel)|Microsoft Learn
https://learn.microsoft.com/ja-jp/office/vba/api/excel.range.find
XlFindLookIn 列挙型 (Excel)|Microsoft Learn
https://learn.microsoft.com/ja-jp/office/vba/api/excel.xlfindlookin
XlSearchOrder 列挙型 (Excel)|Microsoft Learn
https://learn.microsoft.com/ja-jp/office/vba/api/excel.xlsearchorder
Worksheet.UsedRange プロパティ (Excel)|Microsoft Learn
https://learn.microsoft.com/ja-jp/office/vba/api/excel.worksheet.usedrange
Range.SpecialCells メソッド (Excel)|Microsoft Learn
https://learn.microsoft.com/ja-jp/office/vba/api/excel.range.specialcells
XlCellType 列挙型 (Excel)|Microsoft Learn
https://learn.microsoft.com/ja-jp/office/vba/api/excel.xlcelltype
Range.CurrentRegion プロパティ (Excel)|Microsoft Learn
https://learn.microsoft.com/ja-jp/office/vba/api/excel.range.currentregion
データ型の概要|Microsoft Learn
https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/data-type-summary
オーバーフローしました (エラー 6)|Microsoft Learn
https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/overflow-error-6


コメント