VBA最終行の取得はEnd xlUpが基本!3つの方法を比較

スポンサーリンク

「データの最終行って、どうやって取得すればいいの?」

VBAでマクロを書き始めると、必ずぶつかるのがこの疑問ですよね。行数が毎回変わるデータを処理するには、最終行を自動で取得する方法を知っておく必要があります。

でも安心してください。VBAで最終行を取得する方法はいくつかあります。仕組みを理解すれば迷わず使いこなせますよ。この記事では代表的な3つの方法をコード付きで解説します。それぞれの違い・使い分け・よくあるトラブルの対処法もまとめてお伝えしますね。

VBAで最終行を取得する方法3選

最終行を取得する方法は複数ありますが、ここでは実務でよく使われる3つの方法を紹介します。

End(xlUp)で最終行を取得する(最もよく使う方法)

まずはVBAで最終行を取得する定番コードです。

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

このコードは「A列の最終行」を取得しています。仕組みをかんたんに説明すると、こんな流れです。

  1. Rows.Count でシートの最大行数(1,048,576行)を取得する
  2. Cells(1048576, 1) でA列の一番下のセルを指定する
  3. .End(xlUp) で、そこから上方向にデータが入っているセルを探す
  4. .Row で、見つかったセルの行番号を数値で返す

これはExcelで Ctrl + 上矢印キー を押したときと同じ動きです。シートの一番下から上に向かってデータを探すので、途中に空白セルがあっても正確に最終行を見つけられます。

取得した最終行は変数 lastRow に格納しておくと、あとからFor文やDo Loopで繰り返し使えて便利です。変数の基本的な使い方については「VBAの変数の使い方とルールについて解説」で詳しく紹介しています。

列を変更したいとき は、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……と、列番号を数値で指定します。セルの指定方法について詳しく知りたい方は「RangeとCellsはどう違う?使い分けを実例で解説」を参考にしてみてください。

なお、Cells ではなく Range を使った書き方もあります。Range オブジェクトの基本操作は「VBAでのRangeの使い方を基礎から解説」で紹介しています。あわせてチェックしてみてください。

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 はワークシートで「使用されている範囲」を返すプロパティです。データが入力されている範囲全体を自動で判定してくれます。

ここで気になるのが + ActiveSheet.UsedRange.Row - 1 の部分ですよね。これは 1行目が空白のケースに対応するため の計算です。

たとえば、A1〜A3が空白で、A4からデータが始まっているケースを考えてみましょう。

  • UsedRange.Rows.Count → 使用範囲の行数を返す(例: 7行)
  • UsedRange.Row → 使用範囲の開始行番号を返す(例: 4行目)

もし Rows.Count だけで取得すると、結果は「7」になります。でも実際のデータ最終行はA10(4 + 7 – 1 = 10行目)ですよね。だから開始行を足して1を引く補正が必要なんです。

'--- 1行目からデータが始まっている場合はシンプルでもOK ---
lastRow = ActiveSheet.UsedRange.Rows.Count

1行目からデータが始まっていることが確実であれば、上のシンプルな書き方でも問題ありません。ただし、他の人が使うマクロでは、念のため完全版の計算式を使っておくと安心です。

注意点として、UsedRange書式が設定されているだけのセル も「使用済み」とみなします。背景色や罫線だけ入っているセルも対象です。そのため、データの最終行よりも大きな値が返ることがあります。

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

最終行と最終列を同時に取得できるのが、この方法の便利なポイントです。

ただし1つ注意点があります。データが1つもないシートSpecialCells を実行すると、実行時エラー(Runtime Error 1004)が発生します。空シートでも安全に動くようにするには、エラーハンドリングを入れておきましょう。

Dim lastRow As Long
On Error Resume Next
lastRow = Cells.SpecialCells(xlCellTypeLastCell).Row
On Error GoTo 0

If lastRow = 0 Then
    lastRow = 1 'データなしの場合は1行目を返す
End If

On Error Resume Next でエラーを一時的にスキップし、直後の On Error GoTo 0 で通常のエラー処理に戻しています。

3つの方法の違いと使い分け

ここまで紹介した3つの方法を比較表で整理してみましょう。

項目End(xlUp)UsedRangeSpecialCells
取得対象指定した列のデータ最終行シート全体の使用範囲シート全体の使用範囲
空白セルの影響受けにくい受けにくい受けにくい
書式のみのセル無視する含む含む
特定の列を指定できるできないできない
空シートでの動作1を返すエラーなしエラーが発生する
Excel操作での同等機能Ctrl + 上矢印なしCtrl + End
おすすめ度最もおすすめ状況による状況による

結論:迷ったら End(xlUp) を使いましょう。 特定の列に対して正確な最終行を取得でき、書式だけのセルに惑わされないため、実務で最も信頼性が高い方法です。

UsedRange や SpecialCells は「シート全体でどこまでデータがあるか」をざっくり把握したい場面で役立ちます。たとえば、データの範囲を一括でコピーしたいときなどに使うと便利ですよ。

シート指定を明示して誤動作を防ぐ

ここまでのコード例では、対象シートを明示せずに Cells(Rows.Count, 1) と書いていました。この書き方は暗黙的に ActiveSheet(現在アクティブなシート)を参照します。

シートが1つだけのマクロなら問題ありません。ただし 複数シートを扱うマクロ では、意図しないシートの最終行を取得してしまうことがあります。

安全なのは、With ステートメントで対象シートを明示する書き方です。

Sub シート指定で最終行を取得()
    Dim lastRow As Long

    With ThisWorkbook.Worksheets("データ一覧")
        lastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
    End With

    MsgBox "最終行: " & lastRow
End Sub

ポイントは .Cells.Rows.Count の先頭にドット(.)をつけること。このドットが With で指定したシートを参照していることを示します。ドットを忘れると ActiveSheet が参照されてしまうので注意してください。

'--- よくある間違い ---
With ThisWorkbook.Worksheets("データ一覧")
    lastRow = Cells(Rows.Count, 1).End(xlUp).Row  'ドットなし → ActiveSheetを参照してしまう
End With

'--- 正しい書き方 ---
With ThisWorkbook.Worksheets("データ一覧")
    lastRow = .Cells(.Rows.Count, 1).End(xlUp).Row  'ドットあり → 指定シートを参照
End With

シンプルなマクロでは省略しても構いません。ただ、シートを明示しておくと「どのシートを処理しているか」が一目瞭然になります。あとから見返したときにも読みやすいので、習慣にしておくのがおすすめです。

VBA 最終行の取得でよくあるトラブルと対処法

最終行の取得はシンプルに見えますが、いくつかハマりやすいポイントがあります。事前に知っておけば慌てずに済むので、チェックしておきましょう。

空白セルがあると正しく取得できない

End(xlUp) ではなく End(xlDown) を使うと、空白セルがある場合に正しく最終行を取得できません。

'--- End(xlDown) を使った場合(非推奨) ---
lastRow = Cells(1, 1).End(xlDown).Row

このコードはA1セルから下方向にデータを探します。一見すると自然な発想ですが、ここに落とし穴があります。

途中に空白セルがあると、そこで止まってしまうんです。たとえば A1〜A5 にデータがあり、A6 が空白、A7〜A10 にもデータがあるケースで考えてみましょう。End(xlDown)A5 で止まり、本当の最終行 A10 を取得できません。

さらに厄介なのが、データが1行しかない場合 です。A1にしかデータがないと、A2以降がすべて空白なので、シート最終行の1048576行目まで突き抜けてしまいます。

'--- 安全な方法(End(xlUp)を使う) ---
lastRow = Cells(Rows.Count, 1).End(xlUp).Row

下から上に探す End(xlUp) なら、途中の空白セルに影響されません。基本的には End(xlUp) を使うクセ をつけておくのがおすすめです。

取得した値が想定と違うときの確認ポイント

「コードは正しいはずなのに、取得した最終行が想定と違う……」というときは、次の3点を確認してみてください。

  1. 対象の列は正しいかCells(Rows.Count, 1) の列番号(2つ目の引数)が意図した列になっているか確認しましょう。A列のつもりでB列を指定していた、というミスは意外とよくあります。
  1. データが入っていない列を指定していないか — 指定した列にデータが1つも入っていない場合、End(xlUp) は1行目を返します。変数に格納した値が「1」になっていたら、この可能性を疑ってみてください。
  1. 書式だけのセルが残っていないか — UsedRange や SpecialCells を使っている場合は要注意です。過去にデータを削除したセルに書式が残っていると、実際のデータより大きな値が返ります。セルを選択して「クリア」(Delete キーではなく「すべてクリア」)を実行すると解消できます。

実務で使える!最終行取得の活用例

最終行を取得する方法がわかったら、実際のマクロで使ってみましょう。ここでは実務でよく使うパターンを3つ紹介します。

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文の使い方について詳しくは「For~Next文の使い方と実務で役立つ応用テクニック」で解説しています。ループ処理をもっと深く知りたい方はぜひ読んでみてくださいね。

Do Loopで条件付きの繰り返し処理をする

「すべての行」ではなく 特定の条件を満たすまで ループしたいときは、Do Loop が便利です。たとえば、A列を上から順に見ていき、「完了」と書かれたセルが見つかったらループを抜ける処理はこう書けます。

Sub 条件付きループ()
    Dim lastRow As Long
    Dim i As Long

    lastRow = Cells(Rows.Count, 1).End(xlUp).Row
    i = 2 'ヘッダーの次の行から開始

    Do While i <= lastRow
        If Cells(i, 2).Value = "完了" Then
            MsgBox i & "行目で「完了」が見つかりました"
            Exit Do
        End If
        i = i + 1
    Loop
End Sub

For文は「全行を処理する」のが得意ですが、Do Loop は「条件に応じてループを制御する」のが得意です。最終行取得と組み合わせることで、「最終行を超えないように安全にループする」ことができます。

If文での条件分岐については「VBAのIf文の使い方を基礎から解説」を参考にしてみてください。Do Loopの詳しい書き方は「Do Loopの使い方を基礎から解説」で紹介しています。

最終列を取得する方法

行だけでなく、最終列 を取得したい場面もありますよね。考え方は最終行の取得とまったく同じです。

Dim lastCol As Long
lastCol = Cells(1, Columns.Count).End(xlToLeft).Column

違いは以下の3点です。

  • Rows.CountColumns.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と組み合わせれば、データの自動処理がぐっとラクになりますよ。まずは今回紹介したコードをコピーして、ご自身のマクロで試してみてください。

VBAの学習を体系的に進めたい方は「VBAの学習順番を初心者向けに解説」も参考にしてみてくださいね。

タイトルとURLをコピーしました