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

VBAによるピボットテーブルの作成

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

ピボットテーブルは、フィールドを行、列、値にドラッグしてテーブルを要約する機能であり、これらのドラッグ&ドロップ操作にはすべて直接対応するVBAコードが存在します。つまり、新しいデータが到着するたびに、マクロによってピボットテーブルレポート全体をゼロから再構築することが可能です。

図 4.3

ピボットテーブルの作成

Sub BuildProfitPivot()
    Dim wsData As Worksheet, wsPivot As Worksheet
    Dim tbl As ListObject
    Dim pc As PivotCache
    Dim pt As PivotTable
 
    Set wsData = ThisWorkbook.Worksheets("Reports")
    Set tbl = wsData.ListObjects("tblReports")
 
    ' start clean: remove an existing Pivot sheet if this has run before
    On Error Resume Next
    Application.DisplayAlerts = False
    ThisWorkbook.Worksheets("Pivot").Delete
    Application.DisplayAlerts = True
    On Error GoTo 0
 
    Set wsPivot = ThisWorkbook.Worksheets.Add
    wsPivot.Name = "Pivot"
 
    Set pc = ThisWorkbook.PivotCaches.Create( _
        SourceType:=xlDatabase, SourceData:=tbl.Range)
 
    Set pt = pc.CreatePivotTable( _
        TableDestination:=wsPivot.Range("A3"), _
        TableName:="ptProfitByRegion")
 
    With pt
        .PivotFields("Region").Orientation = xlRowField
        .PivotFields("Month").Orientation = xlColumnField
        .AddDataField .PivotFields("Profit"), "Sum of Profit", xlSum
    End With
End Sub
各行の詳細解説
expand arrow
  • DisplayAlerts.Delete の切り替え、DisplayAlerts = False の組み合わせは、「存在すれば削除」パターンの安全な実装方法:存在しないシートを削除しようとすると通常はエラーが発生しマクロが停止しますが、On Error Resume Next によりその特定のエラーを無視して処理を継続します。Error GoTo 0 は、Excel の「このシートを本当に削除しますか?」という確認ポップアップを非表示にします。
  • 直後の On Error Resume Next で通常のエラー報告に戻します。On Error Resume Next を Sub の残り全体で有効にしたままだと、後続の無関係なエラーもすべて黙って無視されてしまうため、これは避けるべき落とし穴です。
  • ThisWorkbook.PivotCaches.Create はテーブルデータのスナップショット(PivotCache)を作成します。これは PivotTable そのものではなく、すべての PivotTable が内部的に基づくオブジェクトです。
  • pc.CreatePivotTable は、そのスナップショットを実際に表示可能な PivotTable に変換します。新しい Pivot シートの A3 セルから配置され、ptProfitByRegion という名前が付けられるため、後続のコード(たとえば RefreshTable など)で名前指定して再利用できます。
  • PivotFields("Region").Orientation = xlRowField および直下の Month の行は、フィールドリストで Region を行、Month を列にドラッグする操作と同等のコードです。
  • AddDataField は値エリアを埋める処理です。第2引数("Sum of Profit")は Excel が列見出しとして表示するラベルで、xlSum は合計値を集計する指定です(平均や件数ではなく)。

レポートの更新

一度 PivotTable を作成したら、新しいデータが追加されるたびに再作成するのではなく、リフレッシュ(更新)します。これにより高速化され、ユーザーが手動で調整したレイアウトも保持されます。

ThisWorkbook.Worksheets("Pivot").PivotTables("ptProfitByRegion").RefreshTable

この1行で、PivotCache が tblReports の最新状態を読み込み、PivotTable 内のすべての数値が更新されます。ただし、レイアウト(列幅、数値書式、フィールド配置など)はそのまま維持され、Pivot 作成後にユーザーが手動で調整した内容も残ります。これは BuildProfitPivot を再度呼び出して再構築する場合との大きな違いです。再構築するとシートが作り直され、手動調整がすべて消えてしまいます。

ピボットグラフの更新

PivotTable 上に作成した PivotChart は、PivotTable をリフレッシュするたびに自動的にデータが更新されます。そのため、レポート用マクロで PivotTable をリフレッシュするだけで、関連付けられたグラフも常に最新状態を保てます。

Dim pt As PivotTable
Set pt = ThisWorkbook.Worksheets("Pivot").PivotTables("ptProfitByRegion")
pt.RefreshTable
' any PivotChart based on pt updates automatically — no extra code needed

これは次のセクションで扱う通常のグラフと対照的です。通常のグラフは新しいデータを参照させるために SetSourceData の明示的な呼び出しが必要ですが、PivotChart は PivotTable に恒久的にリンクされており、自動的に追従します。ダッシュボードで常に最新の PivotTable 数値を反映したグラフを最小限のコードで実現したい場合、独立したグラフより PivotChart を使う方が一般的に適しています。

課題

  1. BuildProfitPivot をそのまま実行し、「Pivot」シートが新規作成され、行に Region、列に Month が表示されることを確認してください。
  2. 架空の6番目の地域用に tblReports に3月の新しい行を手動で追加し、RefreshTable の1行だけを実行してください。Pivot が再構築されることなく更新されることを確認します。
  3. BuildProfitPivot を修正し、Profit の代わりに Sales を集計し、Region と Month を入れ替えて、Month を行、Region を列にしてください。
ヘルパー
expand arrow

以下は、tblReports に 6 番目の地域を新しい 3 月の行として追加するコード例です。手入力ではなく、ListRows.Add を使用しています。

Sub AddSixthRegion()
    Dim tbl As ListObject
    Dim newRow As ListRow

    Set tbl = ThisWorkbook.Worksheets("Reports").ListObjects("tblReports")
    Set newRow = tbl.ListRows.Add

    newRow.Range(1, 1).Value = "March"        ' Month
    newRow.Range(1, 2).Value = "Southwest"    ' Region
    newRow.Range(1, 3).Value = 41500          ' Sales
    newRow.Range(1, 4).Value = 28200          ' Expenses
    newRow.Range(1, 5).Value = 13300          ' Profit
    newRow.Range(1, 6).Value = 39000          ' Target
End Sub

このマクロを一度実行した後、前章の RefreshProfitPivot サブプロシージャを実行してください。ピボットテーブルに North、South、East、West、Central に加えて新しい行として "Southwest" が表示されるはずです。ピボット作成用マクロ自体には一切手を加えていません。

ヒント
expand arrow

1. BuildProfitPivot をそのまま実行する場合

  • 本章に記載された Sub をそのままコピーしてモジュールに貼り付け、一度実行します。
  • Project Explorer またはシートタブを確認すると、"Pivot" という名前の新しいシートが作成されているはずです。行方向に Region、列方向に Month が並び、Profit が集計されています。

2. 6 番目の地域を追加し、リフレッシュのみ行う場合

  • 新しい行をワークシートに直接入力します(コードは使いません)。tblReports の一番下に、架空の地域 "Southwest" の 3 月分の行を追加します。
  • BuildProfitPivot を再実行しないでください。これを実行すると Pivot シート全体が削除・再作成されてしまい、この演習の目的が失われます。
  • 代わりに、章で紹介した一行だけの RefreshTable ステートメントのみを実行します。既存のピボットテーブル名を参照する必要がありますが、これは章のリフレッシュ例と同じ方法です。

3. フィールドの入れ替えと集計値の変更

  • With pt ブロック内の 3 行を変更します。どのフィールドを xlRowField、どれを xlColumnField にするか、AddDataField でどのフィールドを集計するかを指定します。
  • この修正版には異なる Sub 名と異なる TableName を付けてください。同じ名前を使うとエラーになるか、最初のピボットテーブルが上書きされてしまいます。
  • AddDataField のラベル(第 2 引数、例: "Sum of Profit")は表示用テキストなので、実際に集計する内容に合わせて変更してください。
解答例
expand arrow

ポイント 2 — 6 番目の地域の行を手動で追加した後、次のコードのみを実行します。

Sub RefreshProfitPivot()
    ThisWorkbook.Worksheets("Pivot").PivotTables("ptProfitByRegion").RefreshTable
End Sub

ポイント 3 — 別バージョンの修正版:

Sub BuildSalesPivotByMonth()
    Dim wsData As Worksheet, wsPivot As Worksheet
    Dim tbl As ListObject
    Dim pc As PivotCache
    Dim pt As PivotTable

    Set wsData = ThisWorkbook.Worksheets("Reports")
    Set tbl = wsData.ListObjects("tblReports")

    On Error Resume Next
    Application.DisplayAlerts = False
    ThisWorkbook.Worksheets("SalesPivot").Delete
    Application.DisplayAlerts = True
    On Error GoTo 0

    Set wsPivot = ThisWorkbook.Worksheets.Add
    wsPivot.Name = "SalesPivot"

    Set pc = ThisWorkbook.PivotCaches.Create( _
        SourceType:=xlDatabase, SourceData:=tbl.Range)

    Set pt = pc.CreatePivotTable( _
        TableDestination:=wsPivot.Range("A3"), _
        TableName:="ptSalesByMonth")

    With pt
        .PivotFields("Month").Orientation = xlRowField
        .PivotFields("Region").Orientation = xlColumnField
        .AddDataField .PivotFields("Sales"), "Sum of Sales", xlSum
    End With
End Sub

BuildSalesPivotByMonth を実行すると、新しい "SalesPivot" シートが作成され、行方向に Month、列方向に Region、集計値として Sales の合計が表示されます。これは元のレイアウトの鏡像となります。

すべて明確でしたか?

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

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

セクション 4.  3

AIに質問する

expand

AIに質問する

ChatGPT

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

VBAによるピボットテーブルの作成

ピボットテーブルは、フィールドを行、列、値にドラッグしてテーブルを要約する機能であり、これらのドラッグ&ドロップ操作にはすべて直接対応するVBAコードが存在します。つまり、新しいデータが到着するたびに、マクロによってピボットテーブルレポート全体をゼロから再構築することが可能です。

図 4.3

ピボットテーブルの作成

Sub BuildProfitPivot()
    Dim wsData As Worksheet, wsPivot As Worksheet
    Dim tbl As ListObject
    Dim pc As PivotCache
    Dim pt As PivotTable
 
    Set wsData = ThisWorkbook.Worksheets("Reports")
    Set tbl = wsData.ListObjects("tblReports")
 
    ' start clean: remove an existing Pivot sheet if this has run before
    On Error Resume Next
    Application.DisplayAlerts = False
    ThisWorkbook.Worksheets("Pivot").Delete
    Application.DisplayAlerts = True
    On Error GoTo 0
 
    Set wsPivot = ThisWorkbook.Worksheets.Add
    wsPivot.Name = "Pivot"
 
    Set pc = ThisWorkbook.PivotCaches.Create( _
        SourceType:=xlDatabase, SourceData:=tbl.Range)
 
    Set pt = pc.CreatePivotTable( _
        TableDestination:=wsPivot.Range("A3"), _
        TableName:="ptProfitByRegion")
 
    With pt
        .PivotFields("Region").Orientation = xlRowField
        .PivotFields("Month").Orientation = xlColumnField
        .AddDataField .PivotFields("Profit"), "Sum of Profit", xlSum
    End With
End Sub
各行の詳細解説
expand arrow
  • DisplayAlerts.Delete の切り替え、DisplayAlerts = False の組み合わせは、「存在すれば削除」パターンの安全な実装方法:存在しないシートを削除しようとすると通常はエラーが発生しマクロが停止しますが、On Error Resume Next によりその特定のエラーを無視して処理を継続します。Error GoTo 0 は、Excel の「このシートを本当に削除しますか?」という確認ポップアップを非表示にします。
  • 直後の On Error Resume Next で通常のエラー報告に戻します。On Error Resume Next を Sub の残り全体で有効にしたままだと、後続の無関係なエラーもすべて黙って無視されてしまうため、これは避けるべき落とし穴です。
  • ThisWorkbook.PivotCaches.Create はテーブルデータのスナップショット(PivotCache)を作成します。これは PivotTable そのものではなく、すべての PivotTable が内部的に基づくオブジェクトです。
  • pc.CreatePivotTable は、そのスナップショットを実際に表示可能な PivotTable に変換します。新しい Pivot シートの A3 セルから配置され、ptProfitByRegion という名前が付けられるため、後続のコード(たとえば RefreshTable など)で名前指定して再利用できます。
  • PivotFields("Region").Orientation = xlRowField および直下の Month の行は、フィールドリストで Region を行、Month を列にドラッグする操作と同等のコードです。
  • AddDataField は値エリアを埋める処理です。第2引数("Sum of Profit")は Excel が列見出しとして表示するラベルで、xlSum は合計値を集計する指定です(平均や件数ではなく)。

レポートの更新

一度 PivotTable を作成したら、新しいデータが追加されるたびに再作成するのではなく、リフレッシュ(更新)します。これにより高速化され、ユーザーが手動で調整したレイアウトも保持されます。

ThisWorkbook.Worksheets("Pivot").PivotTables("ptProfitByRegion").RefreshTable

この1行で、PivotCache が tblReports の最新状態を読み込み、PivotTable 内のすべての数値が更新されます。ただし、レイアウト(列幅、数値書式、フィールド配置など)はそのまま維持され、Pivot 作成後にユーザーが手動で調整した内容も残ります。これは BuildProfitPivot を再度呼び出して再構築する場合との大きな違いです。再構築するとシートが作り直され、手動調整がすべて消えてしまいます。

ピボットグラフの更新

PivotTable 上に作成した PivotChart は、PivotTable をリフレッシュするたびに自動的にデータが更新されます。そのため、レポート用マクロで PivotTable をリフレッシュするだけで、関連付けられたグラフも常に最新状態を保てます。

Dim pt As PivotTable
Set pt = ThisWorkbook.Worksheets("Pivot").PivotTables("ptProfitByRegion")
pt.RefreshTable
' any PivotChart based on pt updates automatically — no extra code needed

これは次のセクションで扱う通常のグラフと対照的です。通常のグラフは新しいデータを参照させるために SetSourceData の明示的な呼び出しが必要ですが、PivotChart は PivotTable に恒久的にリンクされており、自動的に追従します。ダッシュボードで常に最新の PivotTable 数値を反映したグラフを最小限のコードで実現したい場合、独立したグラフより PivotChart を使う方が一般的に適しています。

課題

  1. BuildProfitPivot をそのまま実行し、「Pivot」シートが新規作成され、行に Region、列に Month が表示されることを確認してください。
  2. 架空の6番目の地域用に tblReports に3月の新しい行を手動で追加し、RefreshTable の1行だけを実行してください。Pivot が再構築されることなく更新されることを確認します。
  3. BuildProfitPivot を修正し、Profit の代わりに Sales を集計し、Region と Month を入れ替えて、Month を行、Region を列にしてください。
ヘルパー
expand arrow

以下は、tblReports に 6 番目の地域を新しい 3 月の行として追加するコード例です。手入力ではなく、ListRows.Add を使用しています。

Sub AddSixthRegion()
    Dim tbl As ListObject
    Dim newRow As ListRow

    Set tbl = ThisWorkbook.Worksheets("Reports").ListObjects("tblReports")
    Set newRow = tbl.ListRows.Add

    newRow.Range(1, 1).Value = "March"        ' Month
    newRow.Range(1, 2).Value = "Southwest"    ' Region
    newRow.Range(1, 3).Value = 41500          ' Sales
    newRow.Range(1, 4).Value = 28200          ' Expenses
    newRow.Range(1, 5).Value = 13300          ' Profit
    newRow.Range(1, 6).Value = 39000          ' Target
End Sub

このマクロを一度実行した後、前章の RefreshProfitPivot サブプロシージャを実行してください。ピボットテーブルに North、South、East、West、Central に加えて新しい行として "Southwest" が表示されるはずです。ピボット作成用マクロ自体には一切手を加えていません。

ヒント
expand arrow

1. BuildProfitPivot をそのまま実行する場合

  • 本章に記載された Sub をそのままコピーしてモジュールに貼り付け、一度実行します。
  • Project Explorer またはシートタブを確認すると、"Pivot" という名前の新しいシートが作成されているはずです。行方向に Region、列方向に Month が並び、Profit が集計されています。

2. 6 番目の地域を追加し、リフレッシュのみ行う場合

  • 新しい行をワークシートに直接入力します(コードは使いません)。tblReports の一番下に、架空の地域 "Southwest" の 3 月分の行を追加します。
  • BuildProfitPivot を再実行しないでください。これを実行すると Pivot シート全体が削除・再作成されてしまい、この演習の目的が失われます。
  • 代わりに、章で紹介した一行だけの RefreshTable ステートメントのみを実行します。既存のピボットテーブル名を参照する必要がありますが、これは章のリフレッシュ例と同じ方法です。

3. フィールドの入れ替えと集計値の変更

  • With pt ブロック内の 3 行を変更します。どのフィールドを xlRowField、どれを xlColumnField にするか、AddDataField でどのフィールドを集計するかを指定します。
  • この修正版には異なる Sub 名と異なる TableName を付けてください。同じ名前を使うとエラーになるか、最初のピボットテーブルが上書きされてしまいます。
  • AddDataField のラベル(第 2 引数、例: "Sum of Profit")は表示用テキストなので、実際に集計する内容に合わせて変更してください。
解答例
expand arrow

ポイント 2 — 6 番目の地域の行を手動で追加した後、次のコードのみを実行します。

Sub RefreshProfitPivot()
    ThisWorkbook.Worksheets("Pivot").PivotTables("ptProfitByRegion").RefreshTable
End Sub

ポイント 3 — 別バージョンの修正版:

Sub BuildSalesPivotByMonth()
    Dim wsData As Worksheet, wsPivot As Worksheet
    Dim tbl As ListObject
    Dim pc As PivotCache
    Dim pt As PivotTable

    Set wsData = ThisWorkbook.Worksheets("Reports")
    Set tbl = wsData.ListObjects("tblReports")

    On Error Resume Next
    Application.DisplayAlerts = False
    ThisWorkbook.Worksheets("SalesPivot").Delete
    Application.DisplayAlerts = True
    On Error GoTo 0

    Set wsPivot = ThisWorkbook.Worksheets.Add
    wsPivot.Name = "SalesPivot"

    Set pc = ThisWorkbook.PivotCaches.Create( _
        SourceType:=xlDatabase, SourceData:=tbl.Range)

    Set pt = pc.CreatePivotTable( _
        TableDestination:=wsPivot.Range("A3"), _
        TableName:="ptSalesByMonth")

    With pt
        .PivotFields("Month").Orientation = xlRowField
        .PivotFields("Region").Orientation = xlColumnField
        .AddDataField .PivotFields("Sales"), "Sum of Sales", xlSum
    End With
End Sub

BuildSalesPivotByMonth を実行すると、新しい "SalesPivot" シートが作成され、行方向に Month、列方向に Region、集計値として Sales の合計が表示されます。これは元のレイアウトの鏡像となります。

すべて明確でしたか?

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

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

セクション 4.  3
some-alt