【VBA】月次報告書をExcelで自動生成する方法(コピペOK)

VBA
スポンサーリンク

スポンサーリンク

この記事でできること

VBAでデータシートから月次報告書テンプレートに自動転記し、PDF出力できるようになる。

  • 対象:毎月の報告書をコピペで作っている人
  • 所要時間:コピペ → 実行まで5分

どんな場面で使う?

  • 毎月の売上データを集計してテンプレートに転記し、上長に提出する月次報告書を自動化したいとき
  • 部門別・拠点別の実績をまとめたPDF報告書を一括で出力したいとき
  • 前月比や達成率などの計算をVBAで自動化してヒューマンエラーをなくしたいとき
  • 報告書にグラフを自動挿入して、見栄えの良い資料をワンクリックで作りたいとき

完成イメージ(Before / After)

Before(手作業)

操作 時間
データシートから対象月の数値を目視で拾う 15分
テンプレートに1項目ずつ転記 20分
グラフのデータ範囲を手動で更新 10分
PDF保存して上長に提出 5分

合計50分。転記ミスで差し戻されると、さらに30分ロス。

After(VBA実行後)

  1. 対象月を選んでマクロを実行する
  2. データが自動で抽出・集計・転記される
  3. グラフが自動更新される
  4. PDFが保存される
  5. 3分で完了。転記ミスゼロ

データシート(入力するデータ):

A B C D E
1 年月 売上 原価 経費 利益
2 2026/01 5000000 3000000 800000 1200000
3 2026/02 5500000 3200000 850000 1450000
4 2026/03 6000000 3500000 900000 1600000

出力されるPDF:


月次報告書PDF\
  └── 月次報告書_2026年03月.pdf

毎月の報告書を手で作っていた時期がある。データシートから数値を拾って、テンプレートに1セルずつコピペして、グラフの範囲を直して、PDFに変換。正直、月初の報告書作成が憂鬱だった。しかも一度、前月のデータを転記してしまい上長に指摘されたことがある。

VBAで自動化してからは、月を選んで実行するだけ。50分→3分になった。転記ミスもゼロ。月初のストレスがなくなった。

同じように毎月の報告書で時間を取られている人に、この自動化を試してほしい。まずは固定データの転記から始めよう。

データシート → テンプレート転記 → PDF出力。この流れをVBAで自動化する。

事前準備

シート構成を用意する

このマクロは2つのシートを使う。

「データ」シート — 月別の実績データ

内容
A列 年月 2026/03
B列 売上 6000000
C列 原価 3500000
D列 経費 900000
E列 利益 1600000
  • 1行目はヘッダー。データは2行目から入力する
  • A列は日付型で入力する(年月の1日を入力:2026/03/01)

「報告書」シート — テンプレート(転記先)

セル 内容
C3 報告書タイトル(例:2026年03月 月次報告書)
C6 売上
C7 原価
C8 経費
C9 利益
C10 利益率

テンプレートのレイアウトは自由に変更してよい。重要なのは転記先のセル位置を合わせること。

バックアップを取る

テンプレートシートにデータを上書きする処理のため、実行前にファイルのコピーを取っておくこと。テスト用のダミーデータで動作確認してから本番データで実行することを強く推奨する。

Excelをマクロ有効ブック(.xlsm)で保存する

拡張子が .xlsx のままだとマクロは保存できない。

  1. 「ファイル」→「名前を付けて保存」
  2. ファイルの種類を「Excelマクロ有効ブック (*.xlsm)」に変更
  3. 保存

手順(コピペ → 実行まで約5分)

VBE(コードを書く画面)を開く

  1. Excelで Alt + F11 を押す
  2. VBE(Visual Basic Editor)が開く

標準モジュールを挿入する

  1. VBEのメニュー →「挿入」→「標準モジュール」
  2. 白い画面(コードウィンドウ)が表示される

コードを貼り付けて実行する

  1. コードウィンドウに、下のコードをそのままコピペする
  2. コード内の書き換えポイント(★マーク)を自分の環境に合わせて変更する
  3. Alt + F8 → マクロ名を選んで「実行」

コード(最小版)– データシートからテンプレートに転記

まず最新月のデータを1件だけ転記して動作確認する。月選択もPDF保存もないシンプルな構成。

セルの転記の基本はセルの転記を自動化する方法を参照。テンプレートの考え方はExcelで請求書を自動作成する方法と同じパターン。


Sub 月次報告書を作成する()
    Dim wsData As Worksheet
    Dim wsReport As Worksheet
    Dim lastRow As Long

    Set wsData = Worksheets("データ")
    Set wsReport = Worksheets("報告書")

    ' ★ 最終行を取得(A列で判定)
    lastRow = wsData.Cells(wsData.Rows.Count, 1).End(xlUp).Row

    If lastRow < 2 Then
        MsgBox "データシートにデータがありません。", vbExclamation
        Exit Sub
    End If

    ' 最終行(最新月)のデータを転記
    Dim sales As Double
    Dim cost As Double
    Dim expense As Double
    Dim profit As Double

    sales = wsData.Cells(lastRow, 2).Value    ' 売上
    cost = wsData.Cells(lastRow, 3).Value     ' 原価
    expense = wsData.Cells(lastRow, 4).Value  ' 経費
    profit = wsData.Cells(lastRow, 5).Value   ' 利益

    With wsReport
        ' ★ タイトル
        .Range("C3").Value = Format(wsData.Cells(lastRow, 1).Value, "yyyy年mm月") & " 月次報告書"
        ' ★ 各項目を転記
        .Range("C6").Value = sales
        .Range("C7").Value = cost
        .Range("C8").Value = expense
        .Range("C9").Value = profit
        ' 利益率(売上がゼロの場合はゼロ)
        If sales <> 0 Then
            .Range("C10").Value = profit / sales
        Else
            .Range("C10").Value = 0
        End If
    End With

    wsReport.Activate
    MsgBox "月次報告書を作成しました。"
End Sub

書き換えポイント

# 書き換え箇所 初期値 説明
1 Worksheets("データ") データ 実績データのシート名
2 Worksheets("報告書") 報告書 テンプレートのシート名
3 .Range("C3") C3, C6〜C10 テンプレート側の転記先セル
4 wsData.Cells(lastRow, 2) 列2〜5 データ側の列番号

動作確認

  1. 「データ」シートに最低1行のテストデータを入力する
  2. マクロを実行する
  3. 「報告書」シートに切り替わり、データが転記されていることを確認する

最小版で転記が確認できたら、次の実務版に進む。

コード(実務版)– 月選択 → データ抽出 → グラフ付き報告書PDF出力

自分はこの方法で毎月の報告書を処理している。月初の作業が50分→3分になった。InputBoxで対象月を選べるので、過去月の再出力にも対応できる。

InputBoxの使い方はInputBoxで条件を入力させて処理を動的に変える方法を参照。グラフ作成の基本はデータ範囲からグラフを自動作成する方法を参照。


Sub 月次報告書を自動生成()
    Dim wsData As Worksheet
    Dim wsReport As Worksheet
    Dim lastRow As Long
    Dim targetMonth As String
    Dim targetDate As Date
    Dim i As Long
    Dim savePath As String
    Dim fileName As String

    Set wsData = Worksheets("データ")
    Set wsReport = Worksheets("報告書")

    ' ★ 対象月を入力(yyyy/mm形式)
    targetMonth = InputBox("対象月を入力してください(例: 2026/03)", _
                           "月次報告書の生成", Format(Date, "yyyy/mm"))
    If targetMonth = "" Then Exit Sub

    ' 入力値の検証
    On Error Resume Next
    targetDate = CDate(targetMonth & "/01")
    On Error GoTo 0
    If targetDate = 0 Then
        MsgBox "日付の形式が正しくありません。" & vbCrLf & _
               "yyyy/mm 形式で入力してください。", vbExclamation
        Exit Sub
    End If

    ' 最終行を取得
    lastRow = wsData.Cells(wsData.Rows.Count, 1).End(xlUp).Row

    If lastRow < 2 Then
        MsgBox "データシートにデータがありません。", vbExclamation
        Exit Sub
    End If

    ' 対象月のデータを検索
    Dim found As Boolean
    Dim sales As Double
    Dim cost As Double
    Dim expense As Double
    Dim profit As Double

    found = False
    For i = 2 To lastRow
        If Format(wsData.Cells(i, 1).Value, "yyyy/mm") = Format(targetDate, "yyyy/mm") Then
            sales = wsData.Cells(i, 2).Value
            cost = wsData.Cells(i, 3).Value
            expense = wsData.Cells(i, 4).Value
            profit = wsData.Cells(i, 5).Value
            found = True
            Exit For
        End If
    Next i

    If Not found Then
        MsgBox Format(targetDate, "yyyy年mm月") & " のデータが見つかりません。", vbExclamation
        Exit Sub
    End If

    ' 確認ダイアログ
    If MsgBox(Format(targetDate, "yyyy年mm月") & " の月次報告書を作成します。" & vbCrLf & _
              "実行しますか?", vbYesNo + vbQuestion) = vbNo Then
        Exit Sub
    End If

    Application.ScreenUpdating = False

    ' --- テンプレートに転記 ---
    With wsReport
        .Range("C3").Value = Format(targetDate, "yyyy年mm月") & " 月次報告書"
        .Range("C6").Value = sales
        .Range("C7").Value = cost
        .Range("C8").Value = expense
        .Range("C9").Value = profit
        If sales <> 0 Then
            .Range("C10").Value = profit / sales
        Else
            .Range("C10").Value = 0
        End If

        ' --- 前月比を計算して転記(ここが追加) ---
        Dim prevDate As Date
        Dim prevSales As Double
        Dim prevProfit As Double
        Dim prevFound As Boolean

        prevDate = DateAdd("m", -1, targetDate)
        prevFound = False

        For i = 2 To lastRow
            If Format(wsData.Cells(i, 1).Value, "yyyy/mm") = Format(prevDate, "yyyy/mm") Then
                prevSales = wsData.Cells(i, 2).Value
                prevProfit = wsData.Cells(i, 5).Value
                prevFound = True
                Exit For
            End If
        Next i

        ' ★ 前月比(D列に出力)
        If prevFound And prevSales <> 0 Then
            .Range("D6").Value = (sales - prevSales) / prevSales  ' 売上前月比
        Else
            .Range("D6").Value = "---"
        End If
        If prevFound And prevProfit <> 0 Then
            .Range("D9").Value = (profit - prevProfit) / prevProfit  ' 利益前月比
        Else
            .Range("D9").Value = "---"
        End If

        ' --- グラフを更新(ここが追加) ---
        ' 直近6ヶ月のデータでグラフを作成
        Dim chartObj As ChartObject
        Dim startRow As Long
        Dim endRow As Long

        ' 対象月を含む直近6ヶ月の範囲を決定
        endRow = 0
        For i = 2 To lastRow
            If Format(wsData.Cells(i, 1).Value, "yyyy/mm") = Format(targetDate, "yyyy/mm") Then
                endRow = i
                Exit For
            End If
        Next i

        startRow = endRow - 5
        If startRow < 2 Then startRow = 2

        ' 既存のグラフを削除
        For Each chartObj In .ChartObjects
            chartObj.Delete
        Next chartObj

        ' ★ グラフを作成(売上・利益の推移)
        Set chartObj = .ChartObjects.Add( _
            Left:=.Range("B13").Left, _
            Top:=.Range("B13").Top, _
            Width:=400, _
            Height:=250)

        With chartObj.Chart
            .ChartType = xlColumnClustered

            ' 売上系列
            .SeriesCollection.NewSeries
            .SeriesCollection(1).Values = wsData.Range(wsData.Cells(startRow, 2), wsData.Cells(endRow, 2))
            .SeriesCollection(1).XValues = wsData.Range(wsData.Cells(startRow, 1), wsData.Cells(endRow, 1))
            .SeriesCollection(1).Name = "売上"

            ' 利益系列
            .SeriesCollection.NewSeries
            .SeriesCollection(2).Values = wsData.Range(wsData.Cells(startRow, 5), wsData.Cells(endRow, 5))
            .SeriesCollection(2).Name = "利益"

            .HasTitle = True
            .ChartTitle.Text = "売上・利益推移(直近" & (endRow - startRow + 1) & "ヶ月)"
            .HasLegend = True
            .Legend.Position = xlLegendPositionBottom
        End With
    End With

    ' --- PDF保存(ここが追加) ---
    savePath = ThisWorkbook.Path & "\月次報告書PDF\"
    If Dir(savePath, vbDirectory) = "" Then
        MkDir savePath
    End If

    fileName = "月次報告書_" & Format(targetDate, "yyyy年mm月") & ".pdf"

    wsReport.ExportAsFixedFormat _
        Type:=xlTypePDF, _
        Filename:=savePath & fileName, _
        Quality:=xlQualityStandard

    Application.ScreenUpdating = True

    MsgBox "月次報告書を作成しました。" & vbCrLf & _
           "保存先: " & savePath & fileName, vbInformation
End Sub

書き換えポイント

# 書き換え箇所 初期値 説明
1 "\月次報告書PDF\" 月次報告書PDF PDF保存先フォルダ名
2 .Range("C3") C3, C6〜C10 テンプレート側の転記先セル
3 .Range("D6"), .Range("D9") D6, D9 前月比の出力先セル
4 Left:=.Range("B13").Left B13 グラフの配置位置(左上セル)
5 Width:=400, Height:=250 400, 250 グラフのサイズ(ピクセル)

実務版で追加した機能

機能 説明 参考記事
月選択(InputBox) 対象月をyyyy/mm形式で入力。過去月の再出力にも対応 InputBoxの使い方
入力値検証 不正な日付形式をチェックしてエラー表示
前月比の自動計算 売上・利益の前月比を算出してD列に出力
グラフ自動生成 直近6ヶ月の売上・利益推移を棒グラフで表示 グラフ自動作成
PDF保存 報告書シートをPDFとして保存 PDF一括変換
確認ダイアログ 対象月を表示してYes/Noで確認

テンプレートの作り方

「報告書」シートのレイアウト例を示す。実際のデザインは自由に変更してよい。重要なのは転記先のセル位置を合わせること。

レイアウト例


行1  : [空白]
行2  : [空白]
行3  : [空白]  C3: 2026年03月 月次報告書
行4  : [空白]
行5  : [空白]  B列:項目名     C列:今月      D列:前月比
行6  : [空白]  売上           C6:5000000    D6:+10.0%
行7  : [空白]  原価           C7:3000000
行8  : [空白]  経費           C8:800000
行9  : [空白]  利益           C9:1200000    D9:+13.0%
行10 : [空白]  利益率         C10:24.0%
行11 : [空白]  ─────────────────
行12 : [空白]
行13 : [空白]  ← ここにグラフが自動配置される

ポイント

  • 金額セル(C6〜C9)の表示形式は #,##0 に設定しておく。書式設定の詳細はセルの書式を一括変更する方法を参照
  • 利益率(C10)の表示形式は 0.0% に設定する
  • 前月比(D6, D9)の表示形式は +0.0%;-0.0% にすると見やすい
  • 印刷範囲を設定しておくとPDFのレイアウトが安定する
  • テンプレートに罫線・タイトル書式・会社ロゴなどを事前に設定しておくと、出力されるPDFの見栄えが良くなる

よくある落とし穴5選

# 症状 原因 対策
1 「データが見つかりません」と表示される A列の年月がテキスト形式になっている セルを選択 →「データ」→「区切り位置」→「完了」で日付型に変換。または CDate() でコード側で変換
2 グラフのデータが表示されない データシートの行数が6行未満で startRow がデータ範囲外になる If startRow < 2 Then startRow = 2 で最小行を保証している。データが1ヶ月分でも動作する
3 PDFにグラフが含まれない グラフの配置が印刷範囲の外にある 「ページレイアウト」→「印刷範囲の設定」でグラフを含む範囲を指定する
4 前月比が「---」になる 前月のデータがデータシートに存在しない 前月データがない場合は「---」を表示する仕様。データを追加するか、表示テキストを変更する
5 2回実行すると前回のグラフが残る 既存グラフの削除処理が抜けている 実務版コードでは ChartObjects をループして既存グラフを削除してから新規作成している
6 利益率が「0」になる 売上がゼロのデータ行を転記した ゼロ除算チェック If sales <> 0 Then を入れている。テストデータにゼロを入れないこと

A列の年月がテキスト形式で格納されていて、Format() で比較しても一致しないパターンにハマったことがある。見た目は「2026/03」なのに中身は文字列。これで20分溶かした。日付型で入力しているかどうかは、セルの表示形式を「標準」にしてシリアル値(例:46143)が表示されるか確認すれば分かる。

VBAで月次報告書のデータが転記されないときの対処法

「マクロを実行したのにテンプレートが空のまま」という場合、原因はA列の年月データがテキスト形式で格納されており、日付比較が一致しないことだ。セルの表示形式を「標準」にしてシリアル値が表示されるか確認し、テキスト形式なら「データ」→「区切り位置」→「完了」で日付型に変換しよう。

VBAで月次報告書のPDF出力が白紙になるときの対処法

「PDFを出力したのに中身が白紙」という場合、印刷範囲がデータやグラフのある領域をカバーしていない可能性が高い。「ページレイアウト」→「印刷範囲の設定」でテンプレート全体を含む範囲を指定し、改ページプレビューでグラフが範囲内に収まっているか確認しよう。

---

FAQ

Q1. データシートに複数の項目列(部門別売上など)を追加したい

列を追加して、転記コードの wsData.Cells(i, 列番号)wsReport.Range("転記先") のペアを増やせばよい。列番号を Const で定数化しておくと管理が楽になる。


Const COL_SALES As Long = 2
Const COL_COST As Long = 3
' 追加列
Const COL_DEPT_A As Long = 6
Const COL_DEPT_B As Long = 7

Q2. グラフの種類を折れ線グラフに変えたい

.ChartType = xlColumnClustered.ChartType = xlLine に変更する。グラフの種類一覧はデータ範囲からグラフを自動作成する方法を参照。

Q3. 複数月分の報告書をまとめてPDF出力したい

InputBoxの代わりにループ処理で対象月を回す。見積書・納品書をテンプレートから自動作成する方法の一括出力パターンが参考になる。


' 例:4月〜3月の12ヶ月分を一括出力
Dim m As Long
For m = 4 To 15
    targetDate = DateSerial(2025, m, 1)
    ' ... 転記・PDF保存処理 ...
Next m

Q4. 報告書に前年同月のデータも載せたい

前月比と同じ要領で、DateAdd("yyyy", -1, targetDate) で前年同月のデータを検索し、別のセルに転記する。

Q5. ボタンから実行したい

マクロをボタン1つで実行する方法を参照。シート上にボタンを設置して OnAction にマクロ名「月次報告書を自動生成」を割り当てる。

---

---

まとめ

この記事では、VBAでデータシートから月次報告書テンプレートにデータを自動転記し、グラフ付きPDFとして出力する方法を解説した。

  • 最小版: 最新月のデータをテンプレートに転記して動作確認
  • 実務版: 月選択 + 前月比計算 + グラフ自動生成 + PDF保存

テスト用のダミーデータで動作確認してから、本番データで実行すること。

関連記事

---

次にやりたくなること

月次報告書の自動生成ができたら、次はこのあたりが気になるはず。

コメント

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