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 に登録する前に Replace や StrConv で表記を統一する処理を挟むと、同一取引先が別々にカウントされる問題を防げます。たとえば「(株)」を「株式会社」に統一するなど、業務のルールに合わせて前処理を入れてください。
出力した一覧をそのままPDF保存したい場合は?
出力シートを ExportAsFixedFormat でPDFに変換できます。
' 請求先一覧シートをPDFで保存
Dim pdfPath As String
pdfPath = ThisWorkbook.Path & "\請求先一覧_" & Format(Date, "yyyymm") & ".pdf"
destSh.ExportAsFixedFormat Type:=xlTypePDF, Filename:=pdfPath
MsgBox "PDFを保存しました:" & pdfPath


