【ExcelVBA・マクロ】エクセルのテーブルをVBAで完全操作:ListObject入門|追加・削除・列名参照・合計行まで【コピペOK】

ListObject入門 ExcelVBA

Excelで表を作るとき、Range("A1")で地道にセルを操作していませんか?実は、テーブル(ListObject)を使えば、見出し行を自動スキップして最終行まで安全にループできるなど、もっとスマートなVBAが書けます。今回は、テーブルをVBAで”完全操作”するための核心オブジェクト「ListObject」を、追加・削除・列名参照・合計行まで丁寧に解説します。

この記事で学べること:

  • テーブルとは何か・なぜVBAで使うと強いのか
  • テーブルの各部位(Range / DataBodyRange / HeaderRowRange / TotalsRowRange)の違い
  • テーブルをVBAで作成する方法(ListObjects.Add)
  • データ行の追加・削除(ListRows.Add / Delete)
  • 列名で列を参照する方法(ListColumns(“列名”))
  • 合計行の表示・集計方法(ShowTotals / TotalsCalculation)
  • 実務で使える「まとめサンプルコード」
  • よくあるエラーと対処法
  • まとめ
スポンサーリンク
スポンサーリンク

テーブルとは?VBAで使う理由

テーブルとは「挿入」→「テーブル」で作成できるExcelの機能です。

Rangeとの違いを表で比較:

比較項目通常のRangeテーブル(ListObject)
最終行取得End(xlUp)で毎回取得が必要DataBodyRangeで自動
見出し行の扱い手動でスキップ(i=2〜)自動的に除外される
列の参照列番号で指定(壊れやすい)列名で指定(列を追加しても壊れない)
データ追加範囲の拡張が必要ListRows.Addで自動拡張

Range("A1:D100")のような固定範囲指定は、データが増減するたびに修正が必要です。テーブルを使えば、こうした煩わしさから解放されます!」

テーブルの構造を理解する(最重要)

.Range

テーブル全体(見出し行+データ行+集計行すべてを含む)

.DataBodyRange

データ部分のみ(見出し行・集計行を除く)← ループ処理はここを使います!

.HeaderRowRange

見出し(ヘッダー)行のみ

.TotalsRowRange

集計行のみ(ShowTotals=True のときのみ存在)

構造を説明する表:

プロパティ含む範囲主な用途
.Range全体(見出し+データ+集計)テーブル全体を選択・書式設定
.DataBodyRangeデータのみループ処理・値のクリア
.HeaderRowRange見出しのみ見出し名の取得・変更
.TotalsRowRange集計行のみ集計行の値取得・書式設定

テーブルをVBAで取得する

Sub テーブルを取得する()
    Dim ws As Worksheet
    Dim tbl As ListObject
    
    Set ws = ActiveSheet
    
    ' 方法1:テーブル名で取得(おすすめ)
    Set tbl = ws.ListObjects("売上テーブル")
    
    ' 方法2:インデックスで取得
    ' Set tbl = ws.ListObjects(1)
    
    ' 方法3:セルから取得
    ' Set tbl = ws.Range("A1").ListObject
    
    MsgBox "テーブル名:" & tbl.Name & vbCrLf & _
           "行数:" & tbl.ListRows.Count & vbCrLf & _
           "列数:" & tbl.ListColumns.Count
End Sub

「テーブル名での取得が最も安全です。名前はExcelの[テーブルデザイン]タブで確認・変更できます。」

テーブルをVBAで作成する(ListObjects.Add)

Sub テーブルを作成する()
    Dim ws As Worksheet
    Dim tbl As ListObject
    
    Set ws = ActiveSheet
    
    ' すでにテーブルが存在するかチェック
    If ws.ListObjects.Count > 0 Then
        MsgBox "すでにテーブルが存在します"
        Exit Sub
    End If
    
    ' A1セルを起点に自動でデータ範囲を検出してテーブル化
    Set tbl = ws.ListObjects.Add( _
        SourceType:=xlSrcRange, _
        Source:=ws.Range("A1").CurrentRegion, _
        XlListObjectHasHeaders:=xlYes)
    
    ' テーブル名を設定
    tbl.Name = "売上テーブル"
    
    ' スタイルを設定(青系のスタイル)
    tbl.TableStyle = "TableStyleMedium2"
    
    MsgBox "テーブルを作成しました!"
End Sub

「CurrentRegionを使うと、データが入っている範囲を自動検出してくれます。」

データ行を追加する(ListRows.Add)【よく使う!】

Sub データ行を追加する()
    Dim ws As Worksheet
    Dim tbl As ListObject
    Dim newRow As ListRow
    
    Set ws = ActiveSheet
    Set tbl = ws.ListObjects("売上テーブル")
    
    ' テーブルの末尾に新しい行を追加
    Set newRow = tbl.ListRows.Add
    
    ' 列名で値を設定(列番号が変わっても壊れない!)
    newRow.Range(tbl.ListColumns("日付").Index) = Date
    newRow.Range(tbl.ListColumns("商品名").Index) = "ノートPC"
    newRow.Range(tbl.ListColumns("数量").Index) = 3
    newRow.Range(tbl.ListColumns("単価").Index) = 80000
    
    MsgBox "データを追加しました!"
End Sub

ListColumns("列名").Indexで列番号を取得するのがポイント。列の順番が変わっても壊れないコードになります。」

特定の行を削除する(ListRows.Delete)

Sub 条件に合う行を削除する()
    Dim ws As Worksheet
    Dim tbl As ListObject
    Dim i As Long
    
    Set ws = ActiveSheet
    Set tbl = ws.ListObjects("売上テーブル")
    
    ' 削除はループを「下から」行うのが鉄則!
    For i = tbl.ListRows.Count To 1 Step -1
        ' 「数量」列が0の行を削除
        If tbl.ListRows(i).Range(tbl.ListColumns("数量").Index) = 0 Then
            tbl.ListRows(i).Delete
        End If
    Next i
    
    MsgBox "削除が完了しました!"
End Sub

「⚠️ 削除ループは必ず「下から(Step -1)」回してください。上から削除するとインデックスがずれてスキップが発生します。」

列名参照でデータ全体を処理する(DataBodyRange活用)

Sub 列名参照でループ処理する()
    Dim ws As Worksheet
    Dim tbl As ListObject
    Dim row As ListRow
    Dim 売上列 As Long
    Dim 判定列 As Long
    
    Set ws = ActiveSheet
    Set tbl = ws.ListObjects("売上テーブル")
    
    ' 列インデックスを変数に格納(可読性UP)
    売上列 = tbl.ListColumns("売上金額").Index
    判定列 = tbl.ListColumns("判定").Index
    
    ' 全データ行をループ(見出しは自動スキップ!)
    For Each row In tbl.ListRows
        If row.Range(売上列) >= 100000 Then
            row.Range(判定列) = "優良"
        ElseIf row.Range(売上列) >= 50000 Then
            row.Range(判定列) = "通常"
        Else
            row.Range(判定列) = "要確認"
        End If
    Next row
    
    MsgBox "判定処理が完了しました!"
End Sub

For Each row In tbl.ListRowsで全データ行をループできます。見出し行のスキップが不要なのでコードが一気にシンプルになります!」

合計行を表示・設定する(ShowTotals / TotalsCalculation)

Sub 合計行を設定する()
    Dim ws As Worksheet
    Dim tbl As ListObject
    
    Set ws = ActiveSheet
    Set tbl = ws.ListObjects("売上テーブル")
    
    ' 合計行を表示
    tbl.ShowTotals = True
    
    ' 「数量」列→合計(SUM)
    tbl.ListColumns("数量").TotalsCalculation = xlTotalsCalculationSum
    
    ' 「売上金額」列→合計(SUM)
    tbl.ListColumns("売上金額").TotalsCalculation = xlTotalsCalculationSum
    
    ' 「商品名」列→件数(COUNT)
    tbl.ListColumns("商品名").TotalsCalculation = xlTotalsCalculationCount
    
    MsgBox "合計行を設定しました!"
End Sub

TotalsCalculationの設定値一覧表:

定数集計方法
xlTotalsCalculationNoneなし(空白)
xlTotalsCalculationSum合計
xlTotalsCalculationAverage平均
xlTotalsCalculationCountデータの個数
xlTotalsCalculationMax最大値
xlTotalsCalculationMin最小値

まとめサンプル:売上テーブルを一括管理するマクロ

(以下の処理をすべて行う実務的なサンプルコード)

  1. テーブルが無ければ作成する
  2. 新しいデータ行を1件追加する
  3. 「数量」が0の行を削除する
  4. 売上金額に応じて「判定」列を自動入力する
  5. 合計行を表示して合計・件数を設定する
Sub 売上テーブルを一括管理する()
    Dim ws As Worksheet
    Dim tbl As ListObject
    Dim newRow As ListRow
    Dim row As ListRow
    Dim i As Long
    
    Set ws = ActiveSheet
    
    '-------------------------------------------
    ' STEP1: テーブルの存在確認・作成
    '-------------------------------------------
    If ws.ListObjects.Count = 0 Then
        Set tbl = ws.ListObjects.Add( _
            SourceType:=xlSrcRange, _
            Source:=ws.Range("A1").CurrentRegion, _
            XlListObjectHasHeaders:=xlYes)
        tbl.Name = "売上テーブル"
        tbl.TableStyle = "TableStyleMedium2"
    Else
        Set tbl = ws.ListObjects(1)
    End If
    
    '-------------------------------------------
    ' STEP2: 新しいデータ行を追加
    '-------------------------------------------
    Set newRow = tbl.ListRows.Add
    newRow.Range(tbl.ListColumns("日付").Index) = Date
    newRow.Range(tbl.ListColumns("商品名").Index) = "サンプル商品"
    newRow.Range(tbl.ListColumns("数量").Index) = 5
    newRow.Range(tbl.ListColumns("単価").Index) = 12000
    newRow.Range(tbl.ListColumns("売上金額").Index) = 5 * 12000
    
    '-------------------------------------------
    ' STEP3: 数量0の行を削除(下からループ)
    '-------------------------------------------
    For i = tbl.ListRows.Count To 1 Step -1
        If tbl.ListRows(i).Range(tbl.ListColumns("数量").Index) = 0 Then
            tbl.ListRows(i).Delete
        End If
    Next i
    
    '-------------------------------------------
    ' STEP4: 売上金額に応じて判定を自動入力
    '-------------------------------------------
    Dim 売上列 As Long: 売上列 = tbl.ListColumns("売上金額").Index
    Dim 判定列 As Long: 判定列 = tbl.ListColumns("判定").Index
    
    For Each row In tbl.ListRows
        Select Case True
            Case row.Range(売上列) >= 100000
                row.Range(判定列) = "優良"
            Case row.Range(売上列) >= 50000
                row.Range(判定列) = "通常"
            Case Else
                row.Range(判定列) = "要確認"
        End Select
    Next row
    
    '-------------------------------------------
    ' STEP5: 合計行の設定
    '-------------------------------------------
    tbl.ShowTotals = True
    tbl.ListColumns("数量").TotalsCalculation = xlTotalsCalculationSum
    tbl.ListColumns("売上金額").TotalsCalculation = xlTotalsCalculationSum
    tbl.ListColumns("商品名").TotalsCalculation = xlTotalsCalculationCount
    
    MsgBox "売上テーブルの管理処理が完了しました!" & vbCrLf & _
           "データ行数:" & tbl.ListRows.Count & "件"
End Sub

よくあるエラーと対処法

エラー内容原因対処法
実行時エラー9
「インデックスが有効範囲にありません」
テーブル名の指定ミスListObjects.Countで確認し、正しいテーブル名を使う
実行時エラー1004テーブル外の操作やテーブルが存在しないテーブルの存在チェック後に操作する
削除時に行がスキップされる上からループで削除しているStep -1(下からループ)に変更する
TotalsRowRangeがNullになるShowTotals=Falseの状態でアクセスShowTotals=Trueにしてからアクセスする
列が見つからない
(ListColumns(“列名”)でエラー)
列名のタイポ or 存在しない列HeaderRowRangeで実際の列名を確認する

まとめ

この記事で学んだことの整理:

  • ListObjectはテーブルを表すオブジェクト。名前や列名で安全に操作できる
  • DataBodyRangeはループ処理の基本。見出し行が自動で除外される
  • ListRows.Addで行追加、ListRows(i).Deleteで行削除(削除は下から!)
  • ListColumns(“列名”).Indexで列番号を取得すれば、列の移動に強いコードになる
  • ShowTotals + TotalsCalculationで集計行をワンクリック設定できる

Range("A1:D100")のような”ベタ書き”から卒業して、テーブルベースのVBAを身につけると、メンテナンス性が格段に上がります。ぜひ今日から使ってみてください!」


スポンサーリンク
スポンサーリンク
ExcelVBA
いがぴをフォローする

コメント

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