Excelテーブルに1行追加したい場合は、VBAでListObjectを取得し、ListRows.Addが返すListRowのRangeへ値を書き込む方法が簡単です。テーブルが空でも新規行のRangeを使えば列に値を代入できます。DataBodyRangeを参照するときは、データ行がない状態を確認してから使いましょう。
ListRows.Addでテーブルの末尾に行を追加する
Excelの「テーブルとして書式設定」で作成した表にはListObjectというオブジェクトが対応します。ワークシート名が「売上」、テーブル名が「SalesTable」、列名が「注文日」「商品」「数量」の例を使います。
Option Explicit
Sub AddSalesRow()
Dim ws As Worksheet
Dim tbl As ListObject
Dim added As ListRow
Set ws = ThisWorkbook.Worksheets("売上")
Set tbl = ws.ListObjects("SalesTable")
Set added = tbl.ListRows.Add
With added.Range
.Cells(1, tbl.ListColumns("注文日").Index).Value = Date
.Cells(1, tbl.ListColumns("商品").Index).Value = "ノート"
.Cells(1, tbl.ListColumns("数量").Index).Value = 3
End With
End Sub
追加した行を示すadded.Rangeへ書くことで、シート全体の最終行を計算せずに済みます。テーブル名と列名は実際のExcelファイルに合わせて変更してください。
用語解説:ListRow
Excelテーブル内の1データ行を表すオブジェクトです。ListRows.Addは追加した行のListRowを返し、そのRangeにアクセスできます。
ListObject・ListRows・DataBodyRangeの違い
| プロパティ・メソッド | 対象 | 使いどころ |
|---|---|---|
| ListObject | Excelテーブル全体 | テーブル名から対象を取得 |
| ListRows | テーブルのデータ行の集合 | 行数の確認や行追加 |
| ListRows.Add | 新しいデータ行 | 末尾・指定位置に新規行を作成 |
| DataBodyRange | 見出しを除くデータ本体 | 既存データ行の一括読み書き |
| ListRow.Range | 特定の1データ行 | 新規行へ値を設定 |
DataBodyRangeは見出し行を含みません。空のテーブルではデータ行の範囲を取得できないため、そのままCellsを参照するコードは避けてください。
空のテーブルでエラーを起こさない確認方法
空テーブルへの追加はListRows.Addで処理できます。一方、追加前にDataBodyRangeを読む処理はNothingチェックを入れると安全です。
Dim tbl As ListObject
Set tbl = ThisWorkbook.Worksheets("売上").ListObjects("SalesTable")
If tbl.DataBodyRange Is Nothing Then
Debug.Print "データ行がまだありません"
Else
Debug.Print "データ行数: " & tbl.ListRows.Count
End If
Dim newRow As ListRow
Set newRow = tbl.ListRows.Add
newRow.Range.Cells(1, 1).Value = Date
ここではNothingなら既存データを読まず、追加したnewRowのRangeから書き込みを開始します。ListRows.Countも使うと、既存の行数で分岐できます。
列番号の固定と列名指定はどう違うか
newRow.Range.Cells(1, 2)はテーブル内の2列目を意味します。列の追加や入れ替えが起こる場合は、ListColumnsで名前からIndexを取得する方法が保守しやすくなります。
Dim productCol As Long
productCol = tbl.ListColumns("商品").Index
newRow.Range.Cells(1, productCol).Value = "ノート"
- 列位置が固定の一時処理なら番号指定で簡潔に書ける。
- 運用中に列順が変わる表なら、列名を基準に指定する。
- 列名の誤記は実行時エラーになるため、テーブル見出しを確認する。
テーブルのデータ範囲とシート全体のセル番号を混同しないことも重要です。ListRow.Range内では1列目がテーブルの先頭列に対応します。
AlwaysInsertで下のセルが動く条件
ListRows.Addは既定で、テーブルの下のセルを下方向へずらして新しい行を追加します。AlwaysInsert:=Falseにすると、直下の行が空ならその行を使ってテーブルを拡張できる場合があります。直下にデータがある場合は移動が必要になります。
Dim newRow As ListRow
Set newRow = tbl.ListRows.Add(AlwaysInsert:=False)
テーブルのすぐ下に別の計算式や入力欄があるブックでは、副作用の確認が必要です。重要なブックはコピーで検証してください。
思いどおりに追加されないときの確認点
- ListObjects("SalesTable")の名前が実際のテーブル名と一致するか。
- シート名が「売上」か、ThisWorkbookとActiveWorkbookを取り違えていないか。
- 指定したListColumnsの見出しが正しいか。
- 追加前にDataBodyRangeを無条件で参照していないか。
- 保護シートやフィルターなど、行追加に影響するExcelの状態を確認する。
- 既存セルを動かしたくない場合、AlwaysInsertの動作と直下のセルを確認する。
「最終行+1」に直接書く方式は、テーブル外へ値を書いてしまう可能性があります。Excelテーブルそのものを拡張したいなら、ListRows.Addで行を作成してください。
関連するVBA記事
RangeとCellsの指定方法を整理しておくと、追加した行のセル参照を正しく記述できます。テーブル外の通常範囲を扱う場合は、最終行の取得方法も役立ちます。
(RangeとCellsを指定する基礎については『VBA RangeとCellsの使い分け判断マップ|配列で50ms高速化』をご参照ください)
(通常のセル範囲で最終行を取得する方法については『VBA最終行取得の鉄板テンプレート|xlUpで空白行も完全攻略!』をご参照ください)
よくある質問とまとめ
テーブルに1行もない場合、ListRows.Addは使える?
使えます。戻り値のListRow.Rangeを使えば、追加した行へ値を書けます。
DataBodyRangeとListRows.Countは同じ?
いいえ。前者はデータ領域のRange、後者はListRowsコレクションの行数です。空テーブルではDataBodyRangeのNothing確認が重要です。
表の途中へ追加したいときは?
ListRows.AddのPosition引数でテーブル内の位置を指定できます。既存の行順や計算式への影響を確認して利用してください。
テーブルへ行を追加するときは、ListObjectからListRows.Addを呼び出し、戻り値のRangeへ値を設定します。DataBodyRangeは既存の行を扱う用途に分け、空テーブルの場合はNothingチェックを行いましょう。
サンプルのテーブル名・列名を自分のブックに置き換え、まずはテスト用の1行追加から確認してください。