最終行の取得(汎用)
「どこまでがデータか」を正確につかむのは、転記・集計・追記のすべてで超重要。初心者でも迷わないように、最短で安全な定番パターンを用途別にまとめました。代表的な方法は End(xlUp)、UsedRange、Find の3系統。状況に応じて使い分けましょう。
最短・高信頼:基準列で End(xlUp)
Sub LastRow_End_xlUp()
'A列を基準に最終行を取得
Dim last As Long
last = Cells(Rows.Count, "A").End(xlUp).Row
MsgBox "最終行は " & last
End Sub
VB- ポイント:
- 考え方: 最下行から上向きに「最初のデータセル」を探す。空白が途中にあっても末尾のデータ位置を返せる。基準列は必ず「必ず埋まる列」を選ぶのが鉄則。
- 使い所: 追記・ループ範囲の動的指定に最適。極端に速いのも利点。
シート全体の「使用範囲」から最終行(UsedRange)
Sub LastRow_UsedRange()
Dim last As Long
last = ActiveSheet.UsedRange.Rows(ActiveSheet.UsedRange.Rows.Count).Row
MsgBox "最終行(UsedRange)は " & last
End Sub
VB- ポイント:
- 考え方: 書式・値・オブジェクトが一度でも使われた領域全体の「最終行」を返す。全体把握に便利だが、書式だけ残骸があると広くなりがち。
- 使い所: 表の設計や全削除・初期化系の把握に向く。データ末尾とはズレるリスクに注意。
最も厳密:Find で最後のデータセルを検索
Sub LastRow_Find()
Dim last As Long, f As Range
Set f = Cells.Find(What:="*", LookIn:=xlFormulas, _
SearchOrder:=xlByRows, SearchDirection:=xlPrevious)
If Not f Is Nothing Then
last = f.Row
MsgBox "最終行(Find)は " & last
Else
MsgBox "データなし(Empty Sheet)"
End If
End Sub
VB- ポイント:
- 考え方: シート内の「最後に使われたセル」を後方検索で取得。空白の混在や複数列のばらつきにも強い厳密派。
- 注意: Find は Nothing 対策と、SearchOrder/Direction の指定が重要。
目的別テンプレート(よくある場面)
'1) 追記:A列基準で最終行の下に書き込む
Sub AppendNewRow()
Dim r As Long
r = Cells(Rows.Count, "A").End(xlUp).Row + 1
Cells(r, "A").Value = "新規"
Cells(r, "B").Value = Date
End Sub
'2) 連続範囲のコピー:基準列Bで可変範囲を組み立て
Sub CopyDynamicRange()
Dim last As Long
last = Cells(Rows.Count, "B").End(xlUp).Row
Range("B2:D" & last).Copy Destination:=Range("F2")
End Sub
'3) 全体把握(初期化):UsedRangeで一括処理
Sub ClearUsedRange()
ActiveSheet.UsedRange.Clear
End Sub
'4) 最終行検出に最も厳密:Find後に範囲を作る
Sub ExportAllData_ByFind()
Dim f As Range, last As Long
Set f = Cells.Find(What:="*", LookIn:=xlFormulas, _
SearchOrder:=xlByRows, SearchDirection:=xlPrevious)
If Not f Is Nothing Then
last = f.Row
Range("A1:E" & last).Copy Destination:=Range("H1")
End If
End Sub
VB- ポイント:
- End(xlUp): 「必ず埋まる列」があるときの王道。
- UsedRange: 初期化・全体処理に便利だが、見た目の残骸で広がりうる。
- Find: シート全体の最後を厳密に取りたい時の解決策。
例題で練習
例題1:売上表(A列がキー)で最終行までループ
Sub Example_LoopSales()
Dim last As Long, r As Long
last = Cells(Rows.Count, "A").End(xlUp).Row
For r = 2 To last
Cells(r, "E").Value = Cells(r, "C").Value * Cells(r, "D").Value '単価×数量
Next
End Sub
VB例題2:空白混在でも最後までコピー(Findで厳密)
Sub Example_CopyToLast_Strict()
Dim f As Range, last As Long
Set f = Cells.Find(What:="*", LookIn:=xlFormulas, _
SearchOrder:=xlByRows, SearchDirection:=xlPrevious)
If Not f Is Nothing Then
last = f.Row
Range("B2:F" & last).Copy Destination:=Range("J2")
End If
End Sub
VB例題3:最終行の下に新規行を作って初期値投入
Sub Example_AppendNew()
Dim r As Long
r = Cells(Rows.Count, "B").End(xlUp).Row + 1
Cells(r, "B").Value = Date
Cells(r, "C").Value = "担当A"
End Sub
VB実務の落とし穴と対策
- 空白・書式の残骸でズレる: UsedRange は過去の書式や罫線で広がる。厳密にデータ末尾が欲しいなら End(xlUp) か Find を優先。
- 基準列の選定ミス: End(xlUp) は「必ず埋まる列」を基準にする。そうでないと途中の空白で誤判定しうる。
- Find の例外処理: 見つからない場合は Nothing になる。必ず判定してから使う。
- 行数上限の違い: Excelの行数はバージョンで異なる(2007以降は 1,048,576 行)。Rows.Count 依存で動くように書くのが安全。
