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 と宣言することで、このセクションで使用するテーブル固有の機能(ListRows、ListColumns、Total 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 オブジェクトに直接適用できる仕組みで、手動で合計を計算するループを書くよりもコード量が少なく、ミスも減ります。
タスク
Section_4_Reports.xlsxを開き、Section_4_Reports.xlsmとして保存し、Reports シートのデータがtblReportsという名前のテーブルであることを確認(テーブル内の任意のセルをクリックし、テーブルデザイン タブが表示されることを確認)。- 5つの地域それぞれに対して4月の行を追加するマクロを作成(
ListRows.Addを使用、合計5行。数値は任意で可)。 ListColumns("Sales").DataBodyRangeとWorksheetFunction.Sumを使い、全行の売上合計を イミディエイトウィンドウ に出力する2つ目のマクロを作成。
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)に出力(ポップアップではなく)。
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行も自動的に含まれる。
フィードバックありがとうございます!
AIに質問する
AIに質問する
何でも質問するか、提案された質問の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 と宣言することで、このセクションで使用するテーブル固有の機能(ListRows、ListColumns、Total 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 オブジェクトに直接適用できる仕組みで、手動で合計を計算するループを書くよりもコード量が少なく、ミスも減ります。
タスク
Section_4_Reports.xlsxを開き、Section_4_Reports.xlsmとして保存し、Reports シートのデータがtblReportsという名前のテーブルであることを確認(テーブル内の任意のセルをクリックし、テーブルデザイン タブが表示されることを確認)。- 5つの地域それぞれに対して4月の行を追加するマクロを作成(
ListRows.Addを使用、合計5行。数値は任意で可)。 ListColumns("Sales").DataBodyRangeとWorksheetFunction.Sumを使い、全行の売上合計を イミディエイトウィンドウ に出力する2つ目のマクロを作成。
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)に出力(ポップアップではなく)。
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行も自動的に含まれる。
フィードバックありがとうございます!