「データの最終行って、どうやって取得すればいいの?」
VBAでマクロを書き始めると、必ずぶつかるのがこの疑問ですよね。行数が毎回変わるデータを処理するには、最終行を自動で取得する方法を知っておく必要があります。
でも安心してください。VBAで最終行を取得する方法はいくつかあり、仕組みを理解すれば迷わず使いこなせるようになります。この記事では代表的な3つの方法をコード付きで解説し、それぞれの違い・使い分け・よくあるトラブルの対処法まで、まとめてお伝えしますね。
VBAで最終行を取得する方法3選
最終行を取得する方法は複数ありますが、ここでは実務でよく使われる3つの方法を紹介します。
End(xlUp)で最終行を取得する(最もよく使う方法)
まずはVBAで最終行を取得する定番コードです。
Dim lastRow As Long
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
このコードは「A列の最終行」を取得しています。仕組みをかんたんに説明すると、こんな流れです。
Rows.Countでシートの最大行数(1,048,576行)を取得するCells(1048576, 1)でA列の一番下のセルを指定する.End(xlUp)で、そこから上方向にデータが入っているセルを探す.Rowで、見つかったセルの行番号を数値で返す
これはExcelで Ctrl + 上矢印キー を押したときと同じ動きです。シートの一番下から上に向かってデータを探すので、途中に空白セルがあっても正確に最終行を見つけられます。
列を変更したいとき は、Cells(Rows.Count, 1) の数値部分を変えてください。
'--- B列の最終行を取得 ---
lastRow = Cells(Rows.Count, 2).End(xlUp).Row
'--- C列の最終行を取得 ---
lastRow = Cells(Rows.Count, 3).End(xlUp).Row
A列=1、B列=2、C列=3……と、列番号を数値で指定します。セルの指定方法について詳しく知りたい方は「【VBA】RangeとCellsはどう違う?使い分けを実例で解説」を参考にしてみてください。
NOTE
Rows.Countはワークシートの最大行数を自動で返してくれます。Excel 2007以降のファイル形式(.xlsx / .xlsm)では1,048,576行、Excel 2003以前の形式(.xls)では65,536行です。Rows.Countを使えばファイル形式に関係なく正しい最大行数が取得できるので、数値を直接書く必要はありません。
UsedRangeで最終行を取得する
2つ目の方法は UsedRange プロパティを使う方法です。
Dim lastRow As Long
lastRow = ActiveSheet.UsedRange.Rows.Count + ActiveSheet.UsedRange.Row - 1
UsedRange はワークシートで「使用されている範囲」を返すプロパティです。データが入力されている範囲全体を自動で判定してくれます。
ただし注意点が1つあります。UsedRange はデータだけでなく、書式が設定されているだけのセル(背景色や罫線だけ入っているセル)も「使用済み」とみなします。そのため、データの最終行よりも大きな値が返ってくることがあります。
'--- シンプルに書く場合(1行目からデータが始まっている前提) ---
lastRow = ActiveSheet.UsedRange.Rows.Count
1行目からデータが始まっている場合は上のシンプルな書き方でも問題ありません。ただし、1行目が空白の場合は結果がずれるので、最初に紹介した完全版の計算式を使うようにしてください。
SpecialCellsで最終行を取得する
3つ目は SpecialCells メソッドを使う方法です。
Dim lastRow As Long
lastRow = Cells.SpecialCells(xlCellTypeLastCell).Row
SpecialCells(xlCellTypeLastCell) は、ワークシートで最後に使用されたセルを返します。これはExcelで Ctrl + End を押したときと同じ動作です。
この方法も UsedRange と同様に、書式のみのセルも考慮されるため、実際のデータの最終行よりも大きな値が返る場合があります。
'--- 最終列も同時に取得したいとき ---
Dim lastRow As Long
Dim lastCol As Long
lastRow = Cells.SpecialCells(xlCellTypeLastCell).Row
lastCol = Cells.SpecialCells(xlCellTypeLastCell).Column
最終行と最終列を同時に取得できるのが、この方法の便利なポイントです。
3つの方法の違いと使い分け
ここまで紹介した3つの方法を比較表で整理してみましょう。
| 項目 | End(xlUp) | UsedRange | SpecialCells |
|---|---|---|---|
| 取得対象 | 指定した列のデータ最終行 | シート全体の使用範囲 | シート全体の使用範囲 |
| 空白セルの影響 | 受けにくい | 受けにくい | 受けにくい |
| 書式のみのセル | 無視する | 含む | 含む |
| 特定の列を指定 | できる | できない | できない |
| Excel操作での同等機能 | Ctrl + 上矢印 | なし | Ctrl + End |
| おすすめ度 | 最もおすすめ | 状況による | 状況による |
結論:迷ったら End(xlUp) を使いましょう。 特定の列に対して正確な最終行を取得でき、書式だけのセルに惑わされないため、実務で最も信頼性が高い方法です。
UsedRange や SpecialCells は「シート全体でどこまでデータがあるか」をざっくり把握したい場面で役立ちます。たとえば、データの範囲を一括でコピーしたいときなどに使うと便利ですよ。
VBA 最終行の取得でよくあるトラブルと対処法
最終行の取得はシンプルに見えますが、いくつかハマりやすいポイントがあります。事前に知っておけば慌てずに済むので、チェックしておきましょう。
空白セルがあると正しく取得できない
End(xlUp) ではなく End(xlDown) を使うと、空白セルがある場合に正しく最終行を取得できません。
'--- End(xlDown) を使った場合 ---
lastRow = Cells(1, 1).End(xlDown).Row
このコードはA1セルから下方向にデータを探します。一見すると自然な発想ですが、ここに落とし穴があります。
途中に空白セルがあると、そこで止まってしまうんです。たとえば A1〜A5 にデータがあり、A6 が空白、A7〜A10 にもデータがある場合、End(xlDown) は A5 を最終行として返します。本当の最終行はA10なのに、途中で止まってしまうんですね。
'--- 安全な方法(End(xlUp)を使う) ---
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
下から上に探す End(xlUp) なら、途中の空白セルに影響されません。基本的には End(xlUp) を使うクセ をつけておくのがおすすめです。
取得した値が想定と違うときの確認ポイント
「コードは正しいはずなのに、取得した最終行が想定と違う……」というときは、次の3点を確認してみてください。
- 対象の列は正しいか —
Cells(Rows.Count, 1)の列番号(2つ目の引数)が意図した列になっているか確認しましょう。A列のつもりでB列を指定していた、というミスは意外とよくあります。
- データが入っていない列を指定していないか — 指定した列にデータが1つも入っていない場合、End(xlUp) は1行目を返します。変数に格納した値が「1」になっていたら、この可能性を疑ってみてください。
- 書式だけのセルが残っていないか — UsedRange や SpecialCells を使っている場合、過去にデータを削除したセルに書式が残っていると、実際のデータより大きな値が返ります。セルを選択して「クリア」(Delete キーではなく「すべてクリア」)を実行すると解消できます。
実務で使える!最終行取得の活用例
最終行を取得する方法がわかったら、実際のマクロで使ってみましょう。ここでは実務でよく使うパターンを2つ紹介します。
For文と組み合わせて全行を処理する
最終行取得の最大の活用場面は、For文と組み合わせたループ処理 です。
Sub 全行処理()
Dim lastRow As Long
Dim i As Long
'--- A列の最終行を取得 ---
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
'--- 2行目から最終行までループ処理 ---
For i = 2 To lastRow
'--- B列に「処理済み」と入力する例 ---
Cells(i, 2).Value = "処理済み"
Next i
MsgBox lastRow - 1 & "件のデータを処理しました"
End Sub
For i = 2 To lastRow とすることで、データが何行あっても自動で全行を処理してくれます。2行目から開始しているのは、1行目がヘッダー行(見出し行)であることを想定しているためです。
For文の使い方について詳しくは「【Excel VBA】For~Next文の使い方と実務で役立つ応用テクニック」で解説しています。ループ処理をもっと深く知りたい方はぜひ読んでみてくださいね。
変数の基礎から確認したい方は「【VBA】日本語は使える?変数の使い方とルールについて解説!!」も参考になりますよ。
最終列を取得する方法
行だけでなく、最終列 を取得したい場面もありますよね。考え方は最終行の取得とまったく同じです。
Dim lastCol As Long
lastCol = Cells(1, Columns.Count).End(xlToLeft).Column
違いは以下の3点です。
Rows.Count→Columns.Count(最大列数を取得)End(xlUp)→End(xlToLeft)(左方向に探す).Row→.Column(列番号を返す)
最終行と最終列を両方取得すれば、データ範囲全体を動的に指定できます。
Sub データ範囲を取得()
Dim lastRow As Long
Dim lastCol As Long
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
lastCol = Cells(1, Columns.Count).End(xlToLeft).Column
'--- データ範囲を選択する例 ---
Range(Cells(1, 1), Cells(lastRow, lastCol)).Select
MsgBox "データ範囲: A1:" & Cells(lastRow, lastCol).Address
End Sub
End プロパティで指定できる方向を一覧にしておきます。
| 定数 | 方向 | 用途 |
|---|---|---|
| xlUp | 上方向 | 最終行の取得 |
| xlDown | 下方向 | 先頭行からの探索(非推奨) |
| xlToLeft | 左方向 | 最終列の取得 |
| xlToRight | 右方向 | 先頭列からの探索 |
まとめ
VBAで最終行を取得する3つの方法を紹介しました。
- End(xlUp) — 最もおすすめ。特定の列の正確な最終行を取得できる
- UsedRange — シート全体の使用範囲を取得。書式のみのセルも含む点に注意
- SpecialCells — Ctrl+Endと同じ動作。最終行と最終列を同時に取得したいときに便利
迷ったら Cells(Rows.Count, 1).End(xlUp).Row を使えば間違いありません。
最終行の取得は、VBAでマクロを作るうえで避けて通れない基本テクニックです。最初のうちはコードを見ながら書いても問題ありません。何度も使ううちに自然と覚えられるので、焦らず実務のなかで身につけていきましょう。
For文やDo Loopと組み合わせれば、データの自動処理がぐっとラクになりますよ。まずは今回紹介したコードをコピーして、ご自身のマクロで試してみてください。
