VBAで月末の請求先一覧を自動作成する方法|Dictionary・合計集計・対象月指定の実用コード

VBAで月末の請求先一覧を自動作成するには、売上データから当月の行だけを抽出し、Dictionary(ディクショナリー)で重複を排除しながら別シートに書き出します。手作業でフィルターをかけてコピーする必要がなくなるため、請求漏れや二重登録のリスクを防ぎながら、毎月同じ品質の一覧を数秒で生成できます。

この記事では、次の内容を順番に解説します。

  • 当月の請求先を重複なく抽出する基本コード
  • Dictionaryの仕組みと使い方
  • 請求先ごとの月間合計金額も一緒に集計する応用コード
  • 対象月をInputBoxで指定できるようにする方法
  • よくある質問(先月分・出力シートの上書き・Dictionary以外の方法等)

当月の請求先を重複なく抽出する基本コードを理解するには?

次のような「売上データ」シートを想定します。A列:日付、B列:請求先名、C列:商品名、D列:金額。

Sub MakeClientList()

    Dim srcSh  As Worksheet
    Dim destSh As Worksheet
    Dim dict   As Object
    Dim lastRow As Long
    Dim i As Long
    Dim rowDest As Long
    Dim tgtMonth As String
    Dim key As Variant

    Set srcSh = Worksheets("売上データ")
    Set dict  = CreateObject("Scripting.Dictionary")

    ' 今月(yyyy/mm)を基準にする
    tgtMonth = Format(Date, "yyyy/mm")

    ' 出力シートをリセット(既存があれば削除して再作成)
    Application.DisplayAlerts = False
    On Error Resume Next
    Worksheets("請求先一覧").Delete
    On Error GoTo 0
    Application.DisplayAlerts = True

    Set destSh = Worksheets.Add
    destSh.Name = "請求先一覧"

    ' ヘッダーを入力
    destSh.Cells(1, 1).Value = "請求先名"

    lastRow = srcSh.Cells(Rows.Count, 1).End(xlUp).Row

    ' 今月分の請求先をDictionaryに登録(重複は自動でスキップ)
    For i = 2 To lastRow
        If Format(srcSh.Cells(i, 1).Value, "yyyy/mm") = tgtMonth Then
            Dim clientName As String
            clientName = Trim(srcSh.Cells(i, 2).Value)
            If clientName <> "" And Not dict.exists(clientName) Then
                dict.Add clientName, True
            End If
        End If
    Next i

    ' 一覧として出力
    rowDest = 2
    For Each key In dict.Keys
        destSh.Cells(rowDest, 1).Value = key
        rowDest = rowDest + 1
    Next key

    MsgBox dict.Count & " 件の請求先一覧を作成しました。", vbInformation, "完了"

End Sub

このコードのポイントは次の通りです。

  • Format(日付, "yyyy/mm") で月を文字列として比較し、当月分だけを対象にする
  • dict.exists(clientName) で登録済みかどうかを確認し、未登録のものだけ追加する
  • 出力前に既存の「請求先一覧」シートを削除して再作成することで、毎回クリーンな状態で出力される
  • 最後に dict.Count で抽出件数を確認できる

Dictionaryの仕組みと使い方を理解するには?

Dictionary(ディクショナリー)は「キーと値のペアを管理するデータ構造」です。同じキーを2回登録しようとしても2回目は無視されるため、重複排除に非常に向いています。

操作コード説明
作成Set dict = CreateObject("Scripting.Dictionary")Dictionaryオブジェクトを用意する
登録確認dict.exists("キー名")すでに登録されているか確認(True/False)
追加dict.Add "キー名", 値キーと値のペアを追加する
件数取得dict.Count登録されているキーの件数
全キー取得dict.Keys登録済みキーの一覧を配列で返す

今回のコードでは値に True を指定していますが、これは「登録済みであることを示すフラグ」として使っています。値の内容は後から使わないため、"" でも 1 でも動作は同じです。

請求先ごとの月間合計金額も集計するには?

請求先名だけでなく、当月の合計金額も一緒に出力したい場合は、Dictionary の値に金額を積み上げます。

Sub MakeClientListWithTotal()

    Dim srcSh  As Worksheet
    Dim destSh As Worksheet
    Dim dict   As Object
    Dim lastRow As Long
    Dim i As Long
    Dim rowDest As Long
    Dim tgtMonth As String
    Dim key As Variant
    Dim clientName As String
    Dim amount As Double

    Set srcSh = Worksheets("売上データ")
    Set dict  = CreateObject("Scripting.Dictionary")

    tgtMonth = Format(Date, "yyyy/mm")

    Application.DisplayAlerts = False
    On Error Resume Next
    Worksheets("請求先一覧").Delete
    On Error GoTo 0
    Application.DisplayAlerts = True

    Set destSh = Worksheets.Add
    destSh.Name = "請求先一覧"

    destSh.Cells(1, 1).Value = "請求先名"
    destSh.Cells(1, 2).Value = "当月合計金額"

    lastRow = srcSh.Cells(Rows.Count, 1).End(xlUp).Row

    For i = 2 To lastRow
        If Format(srcSh.Cells(i, 1).Value, "yyyy/mm") = tgtMonth Then
            clientName = Trim(srcSh.Cells(i, 2).Value)
            amount     = srcSh.Cells(i, 4).Value

            If clientName = "" Then GoTo Continue

            If dict.exists(clientName) Then
                ' 既存のキーに金額を加算
                dict(clientName) = dict(clientName) + amount
            Else
                ' 新規のキーとして金額を登録
                dict.Add clientName, amount
            End If
        End If
Continue:
    Next i

    rowDest = 2
    For Each key In dict.Keys
        destSh.Cells(rowDest, 1).Value = key
        destSh.Cells(rowDest, 2).Value = dict(key)
        destSh.Cells(rowDest, 2).NumberFormatLocal = "#,##0"
        rowDest = rowDest + 1
    Next key

    MsgBox dict.Count & " 件の請求先一覧を作成しました。", vbInformation, "完了"

End Sub

値に金額を累積することで、請求先ごとの月間合計を1回のループで集計できます。SUMIF関数を使わずにVBAだけで完結する点がメリットです。

対象月をInputBoxで指定できるようにするには?

「今月」固定ではなく、任意の月を実行時に指定したい場合は InputBox を追加するだけです。

' 対象月の入力を受け付ける
Dim tgtMonth As String
tgtMonth = InputBox("対象月を入力してください(例:2026/07)", "月次請求先一覧", Format(Date, "yyyy/mm"))

If tgtMonth = "" Then
    MsgBox "キャンセルされました。", vbInformation
    Exit Sub
End If

このコードを基本コードの冒頭(tgtMonth = Format(Date, "yyyy/mm") の代わり)に入れることで、先月・先々月など任意の月の請求先一覧も作成できるようになります。

まとめ

  • 当月の絞り込みは Format(日付, "yyyy/mm") で文字列比較する
  • 重複排除には Dictionary を使い、exists で登録済みを確認してから Add する
  • 合計金額を集計したい場合は Dictionary の 値に金額を累積 する
  • 出力シートは 毎回削除→再作成 することで常にクリーンな状態を保つ
  • 対象月を InputBox で指定すれば 先月・任意の月にも対応 できる

よくある質問

先月分の一覧を作りたい場合は?

tgtMonth = Format(Date, "yyyy/mm") の部分を先月に変えます。

' 先月を対象にする
tgtMonth = Format(DateSerial(Year(Date), Month(Date) - 1, 1), "yyyy/mm")

InputBoxを使う方法にしておくと、コードを書き換えずに任意の月を指定できるため、より汎用的です。

出力シートが削除できずエラーになる場合は?

「請求先一覧」シートが開いたまま保護されていたり、そのシートがアクティブになっていたりするとエラーになることがあります。削除前に Application.DisplayAlerts = False を設定し、On Error Resume Next でエラーをスキップしてから削除する処理を入れておくと安全です(基本コードでは対応済みです)。

Dictionary を使わずに重複排除する方法は?

ループで既存の出力シートを毎回検索する方法もあります。ただしデータ量が多いと処理が遅くなります。また AutoFilter で当月を絞り込んで AdvancedFilter の重複なしコピーを使う方法もありますが、Dictionary を使う方がコードがシンプルで管理しやすくなります。

請求先名の表記ゆれ(株式会社Aと(株)Aなど)がある場合は?

Dictionary に登録する前に ReplaceStrConv で表記を統一する処理を挟むと、同一取引先が別々にカウントされる問題を防げます。たとえば「(株)」を「株式会社」に統一するなど、業務のルールに合わせて前処理を入れてください。

出力した一覧をそのままPDF保存したい場合は?

出力シートを ExportAsFixedFormat でPDFに変換できます。

' 請求先一覧シートをPDFで保存
Dim pdfPath As String
pdfPath = ThisWorkbook.Path & "\請求先一覧_" & Format(Date, "yyyymm") & ".pdf"
destSh.ExportAsFixedFormat Type:=xlTypePDF, Filename:=pdfPath
MsgBox "PDFを保存しました:" & pdfPath

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール