【VBA】データの最終行・最終列を正確に取得する方法(コピペOK)

VBA
スポンサーリンク
スポンサーリンク

この記事でわかること

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. 最終行が正しく取れないときのデバッグ方法は?

MsgBoxDebug.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処理の基盤が固まります。

関連記事

次にやりたくなること

コメント

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