Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
学ぶ Excelテーブルの操作 | テーブルとレポートの自動化
ビジネス自動化のためのExcel VBA

Excelテーブルの操作

メニューを表示するにはスワイプしてください

Excel テーブル(VBA では ListObject と呼ばれる)は、名前付きで自動拡張される範囲であり、フィルター矢印、帯状の行、構造化された列参照が組み込まれています。データがまだテーブルでない場合は、任意のセルを選択して Ctrl+T を押すか、VBA で ListObjects.Add を使ってテーブルを作成します。

ListObject の参照

Dim ws As Worksheet
Dim tbl As ListObject
 
Set ws = ThisWorkbook.Worksheets("Reports")
Set tbl = ws.ListObjects("tblReports")
 
Debug.Print tbl.Range.Address        ' full table including header
Debug.Print tbl.DataBodyRange.Rows.Count   ' data rows only, no header

tbl As ListObject と宣言することで、このセクションで使用するテーブル固有の機能(ListRowsListColumnsTotal Row など)がすべて利用可能になります。2 つの Debug.Print 行の違いに注目してください: tbl.Range はヘッダー行を含むテーブル全体を指し、tbl.DataBodyRange はその下のデータ部分のみを指します。

ほとんどの操作(行の追加、列の合計、レコードのループ処理など)は DataBodyRange を使うべきです。これは、ヘッダーのテキストが誤ってデータ行として扱われるのを防ぐためです。

行の追加

ListRows.Add はテーブル直下に新しい行を追加します。重要なのは、他の列にある構造化参照の数式が自動的に新しい行にも拡張される点で、これが通常の範囲に対するテーブルの大きな利点の一つです。

Dim newRow As ListRow
Set newRow = tbl.ListRows.Add
 
newRow.Range(1, 1).Value = "April"
newRow.Range(1, 2).Value = "North"
newRow.Range(1, 3).Value = 45200
newRow.Range(1, 4).Value = 30750
newRow.Range(1, 5).Value = 14450
newRow.Range(1, 6).Value = 41000

tbl.ListRows.Add は空の行を作成し、それを ListRow オブジェクトとして返します。そのため、次の 6 行は tbl ではなく newRow に書き込みます。newRow.Range(1, 1) は「この新しい行の 1 行目、1 列目」を意味し、インデックスは新しい行ごとに 1 から始まります。これは、シートの最終行を End(xlUp) で探して手動で書き込むよりも優れた方法です。ListRows.Add は常にテーブルの範囲内に正しく追加されるため、Total Row や構造化参照の数式、条件付き書式ルールも自動的に新しい行に適用されます。

レコードの更新

既存の行を更新するには、DataBodyRange をループしてキー列で一致させます。ここでは、予算改定後に 2 月の Central 地域の Target を更新しています:

Dim r As Long
For r = 1 To tbl.DataBodyRange.Rows.Count
    If tbl.DataBodyRange.Cells(r, 1).Value = "February" And _
       tbl.DataBodyRange.Cells(r, 2).Value = "Central" Then
        tbl.DataBodyRange.Cells(r, 6).Value = 52000   ' revised Target
        Exit For
    End If
Next r

これは条件分岐でよく使う「上から下まで、最初に一致したら終了」のパターンを、ハードコード値ではなく実際の行に適用したものです。ループは Month と Region を And で同時にチェックし、両方一致した瞬間に Target 列を更新し、Exit For で無駄な走査を止めます。tbl.DataBodyRange.Cells(r, 1) を使うことで、行番号がテーブル内のデータ範囲に限定され、ここでの 1 行目はテーブルの物理的な開始位置に関係なく、データの最初の行を指します。

テーブル列の参照

構造化参照(ListColumns("Name"))は、列番号で数えるよりも可読性が高く、テーブル編集や列移動があっても壊れにくいです:

Dim profitCol As Range
Set profitCol = tbl.ListColumns("Profit").DataBodyRange
 
Debug.Print Application.WorksheetFunction.Sum(profitCol)
Debug.Print Application.WorksheetFunction.Average(profitCol)

ListColumns("Profit") は列ヘッダーのテキストで列を特定するため、たとえば Profit 列が E 列から F 列に移動してもコードはそのまま動作します。手動で Cells(r, 5) などと数えていると、このような変更で気付かないうちに壊れる可能性があります。Application.WorksheetFunction は、VBA から Excel の標準関数(SUM や AVERAGE など)を Range オブジェクトに直接適用できる仕組みで、手動で合計を計算するループを書くよりもコード量が少なく、ミスも減ります。

タスク

  1. Section_4_Reports.xlsx を開き、Section_4_Reports.xlsm として保存し、Reports シートのデータが tblReports という名前のテーブルであることを確認(テーブル内の任意のセルをクリックし、テーブルデザイン タブが表示されることを確認)。
  2. 5つの地域それぞれに対して4月の行を追加するマクロを作成(ListRows.Add を使用、合計5行。数値は任意で可)。
  3. ListColumns("Sales").DataBodyRangeWorksheetFunction.Sum を使い、全行の売上合計を イミディエイトウィンドウ に出力する2つ目のマクロを作成。
ヒント
expand arrow

1. テーブルの確認とファイルの保存

  • ファイル → 名前を付けて保存 で「Excel マクロ有効ブック(*.xlsm)」を選択して保存するだけでOK — この部分はコード不要。
  • Reports データ内の任意のセルをクリックし、リボンに テーブルデザイン タブが表示されていれば、正しい Excel テーブルであることが確認できる(見た目が似ているだけの通常範囲ではない)。

2. ListRows.Add で5つの4月行を追加

  • ListObject を指す tblReports 変数を用意し、.ListRows.Add を地域ごとに1回ずつ(計5回)呼び出す。もしくは5回ループする方法も可。
  • 各新規行には6つの値(Month, Region, Sales, Expenses, Profit, Target)を位置指定(newRow.Range(1, 1)(1, 2) など)で入力。Chapter 4 の例と同様。
  • 地域名を配列で用意すれば、ほぼ同じ処理を5回書くよりループの方が簡潔。

3. WorksheetFunction で売上合計を算出

  • ListColumns("Sales") でヘッダー名から列を取得し、.DataBodyRange でデータ部分のみを抽出。
  • Application.WorksheetFunction.Sum(...) でその範囲の合計を計算 — ループ不要。
  • Debug.Print で結果をイミディエイトウィンドウ(Ctrl+G)に出力(ポップアップではなく)。
解答例
expand arrow
Option Explicit

Sub AddAprilRows()
    Dim tbl As ListObject
    Dim newRow As ListRow
    Dim regions As Variant
    Dim i As Long

    Set tbl = ThisWorkbook.Worksheets("Reports").ListObjects("tblReports")
    regions = Array("North", "South", "East", "West", "Central")

    For i = 0 To 4
        Set newRow = tbl.ListRows.Add
        newRow.Range(1, 1).Value = "April"
        newRow.Range(1, 2).Value = regions(i)
        newRow.Range(1, 3).Value = 46000 + i * 500   ' Sales — invented
        newRow.Range(1, 4).Value = 31000 + i * 300   ' Expenses — invented
        newRow.Range(1, 5).Value = 15000 + i * 200   ' Profit — invented
        newRow.Range(1, 6).Value = 41000              ' Target — invented
    Next i
End Sub

Sub PrintTotalSales()
    Dim tbl As ListObject
    Dim salesCol As Range

    Set tbl = ThisWorkbook.Worksheets("Reports").ListObjects("tblReports")
    Set salesCol = tbl.ListColumns("Sales").DataBodyRange

    Debug.Print "Total Sales: " & Application.WorksheetFunction.Sum(salesCol)
End Sub

まず AddAprilRows を実行し、その後 PrintTotalSales を実行。DataBodyRange はテーブルの最新状態を常に反映するため、合計値には新しい4月の5行も自動的に含まれる。

すべて明確でしたか?

どのように改善できますか?

フィードバックありがとうございます!

セクション 4.  1

AIに質問する

expand

AIに質問する

ChatGPT

何でも質問するか、提案された質問の1つを試してチャットを始めてください

Excelテーブルの操作

Excel テーブル(VBA では ListObject と呼ばれる)は、名前付きで自動拡張される範囲であり、フィルター矢印、帯状の行、構造化された列参照が組み込まれています。データがまだテーブルでない場合は、任意のセルを選択して Ctrl+T を押すか、VBA で ListObjects.Add を使ってテーブルを作成します。

ListObject の参照

Dim ws As Worksheet
Dim tbl As ListObject
 
Set ws = ThisWorkbook.Worksheets("Reports")
Set tbl = ws.ListObjects("tblReports")
 
Debug.Print tbl.Range.Address        ' full table including header
Debug.Print tbl.DataBodyRange.Rows.Count   ' data rows only, no header

tbl As ListObject と宣言することで、このセクションで使用するテーブル固有の機能(ListRowsListColumnsTotal Row など)がすべて利用可能になります。2 つの Debug.Print 行の違いに注目してください: tbl.Range はヘッダー行を含むテーブル全体を指し、tbl.DataBodyRange はその下のデータ部分のみを指します。

ほとんどの操作(行の追加、列の合計、レコードのループ処理など)は DataBodyRange を使うべきです。これは、ヘッダーのテキストが誤ってデータ行として扱われるのを防ぐためです。

行の追加

ListRows.Add はテーブル直下に新しい行を追加します。重要なのは、他の列にある構造化参照の数式が自動的に新しい行にも拡張される点で、これが通常の範囲に対するテーブルの大きな利点の一つです。

Dim newRow As ListRow
Set newRow = tbl.ListRows.Add
 
newRow.Range(1, 1).Value = "April"
newRow.Range(1, 2).Value = "North"
newRow.Range(1, 3).Value = 45200
newRow.Range(1, 4).Value = 30750
newRow.Range(1, 5).Value = 14450
newRow.Range(1, 6).Value = 41000

tbl.ListRows.Add は空の行を作成し、それを ListRow オブジェクトとして返します。そのため、次の 6 行は tbl ではなく newRow に書き込みます。newRow.Range(1, 1) は「この新しい行の 1 行目、1 列目」を意味し、インデックスは新しい行ごとに 1 から始まります。これは、シートの最終行を End(xlUp) で探して手動で書き込むよりも優れた方法です。ListRows.Add は常にテーブルの範囲内に正しく追加されるため、Total Row や構造化参照の数式、条件付き書式ルールも自動的に新しい行に適用されます。

レコードの更新

既存の行を更新するには、DataBodyRange をループしてキー列で一致させます。ここでは、予算改定後に 2 月の Central 地域の Target を更新しています:

Dim r As Long
For r = 1 To tbl.DataBodyRange.Rows.Count
    If tbl.DataBodyRange.Cells(r, 1).Value = "February" And _
       tbl.DataBodyRange.Cells(r, 2).Value = "Central" Then
        tbl.DataBodyRange.Cells(r, 6).Value = 52000   ' revised Target
        Exit For
    End If
Next r

これは条件分岐でよく使う「上から下まで、最初に一致したら終了」のパターンを、ハードコード値ではなく実際の行に適用したものです。ループは Month と Region を And で同時にチェックし、両方一致した瞬間に Target 列を更新し、Exit For で無駄な走査を止めます。tbl.DataBodyRange.Cells(r, 1) を使うことで、行番号がテーブル内のデータ範囲に限定され、ここでの 1 行目はテーブルの物理的な開始位置に関係なく、データの最初の行を指します。

テーブル列の参照

構造化参照(ListColumns("Name"))は、列番号で数えるよりも可読性が高く、テーブル編集や列移動があっても壊れにくいです:

Dim profitCol As Range
Set profitCol = tbl.ListColumns("Profit").DataBodyRange
 
Debug.Print Application.WorksheetFunction.Sum(profitCol)
Debug.Print Application.WorksheetFunction.Average(profitCol)

ListColumns("Profit") は列ヘッダーのテキストで列を特定するため、たとえば Profit 列が E 列から F 列に移動してもコードはそのまま動作します。手動で Cells(r, 5) などと数えていると、このような変更で気付かないうちに壊れる可能性があります。Application.WorksheetFunction は、VBA から Excel の標準関数(SUM や AVERAGE など)を Range オブジェクトに直接適用できる仕組みで、手動で合計を計算するループを書くよりもコード量が少なく、ミスも減ります。

タスク

  1. Section_4_Reports.xlsx を開き、Section_4_Reports.xlsm として保存し、Reports シートのデータが tblReports という名前のテーブルであることを確認(テーブル内の任意のセルをクリックし、テーブルデザイン タブが表示されることを確認)。
  2. 5つの地域それぞれに対して4月の行を追加するマクロを作成(ListRows.Add を使用、合計5行。数値は任意で可)。
  3. ListColumns("Sales").DataBodyRangeWorksheetFunction.Sum を使い、全行の売上合計を イミディエイトウィンドウ に出力する2つ目のマクロを作成。
ヒント
expand arrow

1. テーブルの確認とファイルの保存

  • ファイル → 名前を付けて保存 で「Excel マクロ有効ブック(*.xlsm)」を選択して保存するだけでOK — この部分はコード不要。
  • Reports データ内の任意のセルをクリックし、リボンに テーブルデザイン タブが表示されていれば、正しい Excel テーブルであることが確認できる(見た目が似ているだけの通常範囲ではない)。

2. ListRows.Add で5つの4月行を追加

  • ListObject を指す tblReports 変数を用意し、.ListRows.Add を地域ごとに1回ずつ(計5回)呼び出す。もしくは5回ループする方法も可。
  • 各新規行には6つの値(Month, Region, Sales, Expenses, Profit, Target)を位置指定(newRow.Range(1, 1)(1, 2) など)で入力。Chapter 4 の例と同様。
  • 地域名を配列で用意すれば、ほぼ同じ処理を5回書くよりループの方が簡潔。

3. WorksheetFunction で売上合計を算出

  • ListColumns("Sales") でヘッダー名から列を取得し、.DataBodyRange でデータ部分のみを抽出。
  • Application.WorksheetFunction.Sum(...) でその範囲の合計を計算 — ループ不要。
  • Debug.Print で結果をイミディエイトウィンドウ(Ctrl+G)に出力(ポップアップではなく)。
解答例
expand arrow
Option Explicit

Sub AddAprilRows()
    Dim tbl As ListObject
    Dim newRow As ListRow
    Dim regions As Variant
    Dim i As Long

    Set tbl = ThisWorkbook.Worksheets("Reports").ListObjects("tblReports")
    regions = Array("North", "South", "East", "West", "Central")

    For i = 0 To 4
        Set newRow = tbl.ListRows.Add
        newRow.Range(1, 1).Value = "April"
        newRow.Range(1, 2).Value = regions(i)
        newRow.Range(1, 3).Value = 46000 + i * 500   ' Sales — invented
        newRow.Range(1, 4).Value = 31000 + i * 300   ' Expenses — invented
        newRow.Range(1, 5).Value = 15000 + i * 200   ' Profit — invented
        newRow.Range(1, 6).Value = 41000              ' Target — invented
    Next i
End Sub

Sub PrintTotalSales()
    Dim tbl As ListObject
    Dim salesCol As Range

    Set tbl = ThisWorkbook.Worksheets("Reports").ListObjects("tblReports")
    Set salesCol = tbl.ListColumns("Sales").DataBodyRange

    Debug.Print "Total Sales: " & Application.WorksheetFunction.Sum(salesCol)
End Sub

まず AddAprilRows を実行し、その後 PrintTotalSales を実行。DataBodyRange はテーブルの最新状態を常に反映するため、合計値には新しい4月の5行も自動的に含まれる。

すべて明確でしたか?

どのように改善できますか?

フィードバックありがとうございます!

セクション 4.  1
some-alt