【VBA】ExcelデータをWordに差し込み印刷する方法(コピペOK)

VBA
スポンサーリンク
スポンサーリンク

この記事でできること

ExcelのデータをWordテンプレートに自動差し込み+印刷(PDF出力)するVBAマクロを作れる。コピペ → 実行まで10分。

対象読者:Excelの一覧データからWordの書類(案内状・通知書・契約書など)を大量に作りたい人。VBAは初心者でOK。

導入

案内状を100人分作る仕事があったとき、自分はExcelの名簿をWordに1人ずつコピペして印刷していた。名前と住所を間違えるのが怖くて、1枚ずつ確認しながら進めるので半日かかっていた。正直しんどかった。

VBAでExcel → Word の差し込みを自動化してからは、100人分でも5分で完了するようになった。転記ミスもゼロ。

この記事で、同じ作業で時間を奪われている人が一気に自動化できるようになればうれしい。

前提条件

– Excel 2016以降 / Microsoft 365

– Word 2016以降 / Microsoft 365

– Windows 10/11

– ファイル保存形式:.xlsm(マクロ有効ブック)

– コードの貼り付け場所:標準モジュール(Excel側)

– 実行方法:マクロ実行(Alt + F8)またはボタン割り当て

– Wordテンプレートファイル(.docx)を事前に用意

どんな場面で使う?

  • 案内状・通知書・契約書などの定型文書をExcelの名簿データから100枚単位で一括作成したいとき
  • 宛名・金額・日付などを1人ずつWordにコピペする手作業をなくしたいとき
  • 差し込み済みの文書を1人1ファイルのPDFとして個別保存したいとき
  • Wordの標準メールマージ機能では対応できない条件分岐やファイル名制御が必要なとき

完成イメージ(Before / After)

Before(手作業)

Excelの名簿 → Wordの案内状テンプレートに1人ずつコピペ → 印刷 or PDF保存 → 100人分繰り返し

After(VBA実行後)

Excelの一覧データを読み取り → Wordテンプレートの {氏名} {住所} などのフィールドに自動挿入 → 全員分のPDFが個別に保存される


【Excelデータ(一覧シート)】
   A列      B列         C列          D列
1  氏名     住所         電話番号      会員番号
2  山田太郎  東京都新宿区  03-1234-5678  A001
3  佐藤花子  大阪府大阪市  06-8765-4321  A002
...

  ↓ VBA実行 ↓

【Wordテンプレート内の {氏名} → 山田太郎 に自動置換】
【Wordテンプレート内の {住所} → 東京都新宿区 に自動置換】
  → PDF保存:案内状_山田太郎.pdf
  → PDF保存:案内状_佐藤花子.pdf
  ...(全員分自動生成)

事前準備

1. Excelデータ(一覧シート)

シート名「データ」に以下の形式でデータを入力する。

セル 内容
A1 氏名
B1 住所
C1 電話番号
D1 会員番号
A2以降 実データを入力

1行目のヘッダー名がWordテンプレートの差し込みフィールド名と一致する必要がある。

2. Wordテンプレート(.docx)

Wordファイルを作成し、差し込みたい箇所に {ヘッダー名} を記入する。


                    ご案内

{氏名} 様

 拝啓 時下ますますご清栄のこととお慶び申し上げます。

 会員番号:{会員番号}
 ご住所:{住所}
 お電話:{電話番号}

 下記の通りご案内申し上げます。
 ...

テンプレートファイルはExcelファイルと同じフォルダに保存する。

手順

  1. Excelのデータシートを作成する(1行目がヘッダー、2行目以降がデータ)
  2. Wordテンプレートを作成し、差し込み箇所に {ヘッダー名} を記入して保存
  3. Excel側で Alt + F11 を押してVBE(コードを書く画面)を開く
  4. 左側のプロジェクトエクスプローラで 「挿入」→「標準モジュール」 を選択
  5. 下のコードをコピペして貼り付ける
  6. コード内の templatePath をWordテンプレートのファイルパスに修正する
  7. Alt + F8 で「MailMergeToWord」を選んで実行
  8. Wordが自動で開き、差し込み結果が表示されることを確認
  9. Ctrl + S.xlsm形式 で保存

ExcelからWordへの転記の基本はExcelの表をWordに自動転記する方法で解説している。まだ読んでいない場合は先にそちらを確認すると理解が早い。

基本コード(単一レコード差し込み)

まずはこれで動く、最小限のコード。Excelの1行目のデータをWordテンプレートに差し込む。


Sub MailMergeToWord()

    Dim wordApp As Object
    Dim wordDoc As Object
    Dim wsData As Worksheet
    Dim templatePath As String
    Dim lastCol As Long
    Dim j As Long
    Dim fieldName As String
    Dim fieldValue As String

    ' テンプレートのパスを設定(★ここを自分の環境に合わせて変更★)
    templatePath = ThisWorkbook.Path & "\テンプレート.docx"

    ' テンプレートファイルの存在確認
    If Dir(templatePath) = "" Then
        MsgBox "テンプレートファイルが見つかりません。" & vbCrLf & _
               templatePath, vbExclamation
        Exit Sub
    End If

    ' データシートを設定
    Set wsData = ThisWorkbook.Sheets("データ")

    ' 最終列を取得
    lastCol = wsData.Cells(1, wsData.Columns.Count).End(xlToLeft).Column

    ' Wordを起動してテンプレートを開く
    Set wordApp = CreateObject("Word.Application")
    wordApp.Visible = True

    Set wordDoc = wordApp.Documents.Open(templatePath)

    ' 1行目のヘッダーをフィールド名として、2行目のデータを差し込み
    For j = 1 To lastCol
        fieldName = "{" & wsData.Cells(1, j).Value & "}"
        fieldValue = CStr(wsData.Cells(2, j).Value)

        ' Word文書内のフィールドを置換
        With wordDoc.Content.Find
            .Text = fieldName
            .Replacement.Text = fieldValue
            .Forward = True
            .Wrap = 1  ' wdFindContinue
            .MatchCase = False
            .MatchWholeWord = False
            .Execute Replace:=2  ' wdReplaceAll
        End With
    Next j

    MsgBox "差し込みが完了しました。Word文書を確認してください。", vbInformation

    ' 後片付け(Wordは開いたまま)
    Set wordDoc = Nothing
    Set wordApp = Nothing

End Sub

ポイントは、Excelの1行目(ヘッダー)を {ヘッダー名} 形式でWordテンプレート内を検索・置換しているところ。Find.Execute Replace:=2 で文書全体を一括置換できる。

実務版コード(全レコードループ+個別PDF保存+差し込みフィールド自動検出)

自分はこの実務版で案内状200通を15分で全部PDFにできた。手作業だったら丸一日かかっていたはず。もっと早く知りたかった。


Sub MailMergeToWordFull()
    '=== 実務版:全レコードループ+個別PDF保存+フィールド自動検出 ===

    Dim wordApp As Object
    Dim wordDoc As Object
    Dim wsData As Worksheet
    Dim templatePath As String
    Dim outputFolder As String
    Dim lastRow As Long
    Dim lastCol As Long
    Dim i As Long
    Dim j As Long
    Dim fieldName As String
    Dim fieldValue As String
    Dim pdfFileName As String
    Dim successCount As Long
    Dim errorCount As Long

    ' テンプレートのパスを設定(★ここを自分の環境に合わせて変更★)
    templatePath = ThisWorkbook.Path & "\テンプレート.docx"

    ' テンプレートファイルの存在確認
    If Dir(templatePath) = "" Then
        MsgBox "テンプレートファイルが見つかりません。" & vbCrLf & _
               templatePath, vbExclamation
        Exit Sub
    End If

    ' ---- ここが追加:PDF出力先フォルダの作成 ----
    outputFolder = ThisWorkbook.Path & "\差し込み結果"
    If Dir(outputFolder, vbDirectory) = "" Then
        MkDir outputFolder
    End If

    ' データシートを設定
    Set wsData = ThisWorkbook.Sheets("データ")

    ' 最終行・最終列を取得
    lastRow = wsData.Cells(wsData.Rows.Count, "A").End(xlUp).Row
    lastCol = wsData.Cells(1, wsData.Columns.Count).End(xlToLeft).Column

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

    ' ---- ここが追加:差し込みフィールドの自動検出 ----
    ' テンプレートを一度開いてフィールドを確認
    Dim fieldNames() As String
    Dim fieldCount As Long
    fieldCount = 0
    ReDim fieldNames(1 To lastCol)

    For j = 1 To lastCol
        If wsData.Cells(1, j).Value <> "" Then
            fieldCount = fieldCount + 1
            fieldNames(fieldCount) = wsData.Cells(1, j).Value
        End If
    Next j

    If fieldCount = 0 Then
        MsgBox "ヘッダー行(1行目)が空です。", vbExclamation
        Exit Sub
    End If

    ' 確認ダイアログ
    Dim msg As String
    msg = "以下の設定で差し込み印刷を実行します。" & vbCrLf & vbCrLf & _
          "データ件数:" & (lastRow - 1) & "件" & vbCrLf & _
          "差し込みフィールド:" & fieldCount & "個" & vbCrLf
    For j = 1 To fieldCount
        msg = msg & "  {" & fieldNames(j) & "}" & vbCrLf
    Next j
    msg = msg & vbCrLf & "PDF出力先:" & outputFolder

    If MsgBox(msg, vbOKCancel + vbQuestion, "実行確認") = vbCancel Then
        Exit Sub
    End If

    ' ---- ここが追加:画面更新を停止 ----
    Application.ScreenUpdating = False
    Application.StatusBar = "差し込み印刷を準備しています..."

    ' Wordを起動(非表示で処理して高速化)
    Set wordApp = CreateObject("Word.Application")
    wordApp.Visible = False

    successCount = 0
    errorCount = 0

    ' ---- ここが追加:全レコードループ ----
    For i = 2 To lastRow

        On Error Resume Next

        ' テンプレートを毎回新しく開く(前のレコードの置換が残らないように)
        Set wordDoc = wordApp.Documents.Open(templatePath, ReadOnly:=True)

        If Err.Number <> 0 Then
            errorCount = errorCount + 1
            Err.Clear
            GoTo NextRecord
        End If

        On Error GoTo 0

        ' 各フィールドを差し込み
        For j = 1 To fieldCount
            fieldName = "{" & fieldNames(j) & "}"
            fieldValue = CStr(wsData.Cells(i, j).Value)

            ' 日付型の場合はフォーマットを適用
            If IsDate(wsData.Cells(i, j).Value) And _
               Not IsEmpty(wsData.Cells(i, j).Value) Then
                fieldValue = Format(wsData.Cells(i, j).Value, "yyyy年mm月dd日")
            End If

            With wordDoc.Content.Find
                .Text = fieldName
                .Replacement.Text = fieldValue
                .Forward = True
                .Wrap = 1  ' wdFindContinue
                .MatchCase = False
                .MatchWholeWord = False
                .Execute Replace:=2  ' wdReplaceAll
            End With
        Next j

        ' ---- ここが追加:個別PDF保存 ----
        ' A列の値をファイル名に使用(A列=氏名の想定)
        pdfFileName = wsData.Cells(i, 1).Value
        ' ファイル名に使えない文字を除去
        pdfFileName = Replace(pdfFileName, "\", "")
        pdfFileName = Replace(pdfFileName, "/", "")
        pdfFileName = Replace(pdfFileName, ":", "")
        pdfFileName = Replace(pdfFileName, "*", "")
        pdfFileName = Replace(pdfFileName, "?", "")
        pdfFileName = Replace(pdfFileName, """", "")
        pdfFileName = Replace(pdfFileName, "<", "")
        pdfFileName = Replace(pdfFileName, ">", "")
        pdfFileName = Replace(pdfFileName, "|", "")

        On Error Resume Next
        wordDoc.ExportAsFixedFormat _
            OutputFileName:=outputFolder & "\" & pdfFileName & ".pdf", _
            ExportFormat:=17  ' wdExportFormatPDF = 17

        If Err.Number = 0 Then
            successCount = successCount + 1
        Else
            errorCount = errorCount + 1
            Err.Clear
        End If
        On Error GoTo 0

        ' Word文書を保存せずに閉じる
        wordDoc.Close SaveChanges:=False
        Set wordDoc = Nothing

NextRecord:
        ' 進捗表示
        Application.StatusBar = "差し込み中... " & (i - 1) & "/" & (lastRow - 1) & "件完了"
        DoEvents

    Next i

    ' Wordを終了
    wordApp.Quit
    Set wordApp = Nothing

    ' 画面更新を復帰
    Application.ScreenUpdating = True
    Application.StatusBar = False

    MsgBox "差し込み印刷が完了しました。" & vbCrLf & vbCrLf & _
           "成功:" & successCount & "件" & vbCrLf & _
           "エラー:" & errorCount & "件" & vbCrLf & _
           "出力先:" & outputFolder, vbInformation

End Sub

大量のレコードを処理するときは、進捗表示があると安心感が違う。ステータスバーの使い方は処理の進捗をステータスバーに表示する方法で詳しく解説している。

ファイルの存在確認(Dir(templatePath) = "")のパターンはファイルやフォルダの存在を確認してから処理する方法と同じ。外部ファイルを扱うマクロでは必須のチェック。

注意:実行前にWordテンプレートの原本をバックアップしてください。基本コードではテンプレートを直接編集するため、保存すると元に戻せません。実務版はReadOnlyで開くので安全です。

落とし穴

# 症状 原因 対策
1 「ファイルが見つかりません」エラー templatePath のパスが間違っている、またはファイル名に全角スペースが入っている Dir(templatePath) で事前に存在確認する。パスはコピペが確実
2 差し込みフィールドが置換されない Excelのヘッダー名とWordテンプレートの {フィールド名} が一致していない(全角/半角、スペースの有無) ヘッダー名を完全一致させる。自分もこれで30分溶かしたことがある。{氏名}{ 氏名 } は別物
3 Wordが裏で大量に起動してPCが固まる エラー発生時に wordApp.Quit が実行されず、Wordプロセスが残る 実務版では On Error Resume Next でエラーを回避しつつ、最後に必ず wordApp.Quit を実行。タスクマネージャーで残ったWordプロセスを手動で終了する場合もある
4 PDFのファイル名に使えない文字でエラーになる 氏名に \ / : * ? " < > ` ` が含まれている 実務版では Replace で禁止文字を除去済み
5 日付が「45000」のようなシリアル値で差し込まれる Excelの日付型がそのまま文字列化されている 実務版では IsDate() で判定し、Format() で変換してから差し込む
6 Wordテンプレートの書式(フォント・サイズ)が崩れる Find.Execute Replace で置換すると、置換後のテキストにフィールド部分の書式が引き継がれないことがある テンプレート内の {フィールド名} に適用した書式は、置換後も基本的に維持される。ただし複数の書式が混在するフィールドは崩れることがあるので、フィールド全体を同じ書式に統一しておく

VBAでWordの差し込みフィールドが置換されないときの対処法

「マクロを実行したのにWordのテンプレートがそのまま」という場合、原因はExcelのヘッダー名とWordテンプレート内の{フィールド名}が一致していないことだ。全角・半角、スペースの有無を含めて完全一致させる必要がある。{氏名}{ 氏名 }は別物なので、コピペでヘッダー名を揃えるのが確実だ。

VBAでWord操作後にWordプロセスが残るときの対処法

「マクロ実行後にPCが重くなる」場合、エラー発生時にwordApp.Quitが呼ばれずWordプロセスがバックグラウンドに残っている可能性がある。On Error GoToでエラーハンドラを用意し、必ずwordApp.QuitSet wordApp = Nothingを実行する終了処理を入れよう。既に残っているプロセスはタスクマネージャーで手動終了する。

---

FAQ

Q1. Word側でブックマーク(Bookmarks)を使う方法との違いは?

A. ブックマーク方式はExcelの表をWordに自動転記する方法で解説している。{フィールド名} 置換方式は設定が簡単だが、同じフィールドを文書内の複数箇所に置けるのが利点。ブックマーク方式は位置が正確だが、Word側の設定がやや手間。用途に応じて使い分ける。

Q2. Wordの差し込み印刷機能(メールマージ)とVBAの違いは?

A. Wordの標準機能でもExcelデータの差し込み印刷はできる。ただしVBAを使うと、個別PDF保存・ファイル名の自動設定・条件分岐など、標準機能ではできない柔軟な処理が可能になる。定期的に同じ処理を繰り返すならVBAが効率的。

Q3. Excelのデータにフィルタをかけて、特定の人だけ差し込みたい

A. ループ内に If 文で条件を追加する。たとえば「D列が"対象"の行だけ処理する」場合:


If wsData.Cells(i, "D").Value = "対象" Then
    ' 差し込み処理
End If

条件が複雑な場合は、複数条件でデータを抽出して別シートにまとめる方法で事前にデータを絞り込んでから差し込む方法もある。

Q4. 差し込み結果をPDFではなくWordファイルで個別保存したい

A. ExportAsFixedFormat の代わりに SaveAs2 を使う。


wordDoc.SaveAs2 outputFolder & "\" & pdfFileName & ".docx", _
    FileFormat:=12  ' wdFormatXMLDocument = 12

Q5. テンプレートに画像(社印など)を入れておいても大丈夫?

A. 大丈夫。テンプレートの画像は差し込み処理では影響を受けない。ただし、フィールド置換によるテキスト量の増減でレイアウトがずれることがあるので、テンプレート設計時にテスト印刷で確認しておくのが安全。自分は最初のテストで社印が2ページ目にずれて焦ったことがある。

---

まとめ

この記事では、ExcelのデータをWordテンプレートの差し込みフィールドに自動挿入して印刷(PDF出力)するVBAマクロを作成した。

  • 基本コード:単一レコードの差し込み(1人分)
  • 実務版:全レコードループ+個別PDF保存+フィールド自動検出+進捗表示

Excel → Word の連携パターンを覚えると、案内状・通知書・契約書・証明書など、あらゆる定型文書の大量作成を自動化できる。

Excelファイル同士の操作で完結する場合はExcelファイルを自動で開いて処理して閉じる方法が参考になる。

---

次にやりたくなること

---

コメント

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