ねらい:月次の「集計→締め処理→レポート→ピボット→バックアップ」を一括で自動化する
月次処理は、日次の積み重ねを「月区切り」で確実に締めて出力することが命です。VBAなら“期間キーの決定→データ取り込み・正規化→集計・KPI作成→レポートとピボット→月次バックアップと版管理”の型にすると、誰が回しても同じ品質になります。初心者でも貼って動くテンプレを、例題付きでかみ砕いて解説します。
共通基盤:期間キー・設定・ログ・安全化
期間キーと設定ユーティリティ
' ModMonthly_Base.bas
Option Explicit
Public Type MonthlyConfig
YearMonth As String ' 例: "2025-12"
SrcFolder As String ' 月次元データの置き場所
OutFolder As String ' 月次レポート出力
BackupFolder As String
RoundMode As String ' "round"/"ceil"/"floor"
End Type
Public Function LoadMonthlyConfig(ByVal year As Long, ByVal month As Long) As MonthlyConfig
Dim c As MonthlyConfig
c.YearMonth = Format(DateSerial(year, month, 1), "yyyy-mm")
c.SrcFolder = ThisWorkbook.Path & "\monthly_in"
c.OutFolder = ThisWorkbook.Path & "\monthly_out"
c.BackupFolder = ThisWorkbook.Path & "\monthly_backup"
c.RoundMode = "round"
LoadMonthlyConfig = c
End Function
Public Function MonthStart(ByVal ym As String) As Date
MonthStart = DateSerial(CLng(Left$(ym, 4)), CLng(Mid$(ym, 6, 2)), 1)
End Function
Public Function MonthEnd(ByVal ym As String) As Date
Dim y As Long: y = CLng(Left$(ym, 4))
Dim m As Long: m = CLng(Mid$(ym, 6, 2))
MonthEnd = DateSerial(y, m + 1, 0) ' 当月末日
End Function
Public Function EnsureFolder(ByVal folderPath As String) As Boolean
On Error Resume Next
If Dir(folderPath, vbDirectory) = "" Then MkDir folderPath
EnsureFolder = (Dir(folderPath, vbDirectory) <> "")
On Error GoTo 0
End Function
Public Sub AppendLog(ByVal logPath As String, ByVal message As String)
Dim f As Integer: f = FreeFile
Open logPath For Append As #f
Print #f, Format(Now, "yyyy-mm-dd hh:nn:ss"); " | "; message
Close #f
End Sub
VB重要部分の深掘り
- 月次キーは “yyyy-mm” を固定。開始日・終了日は関数化して誤差ゼロにします。
- 設定値(フォルダ・丸め・対象月)は1箇所に集約。現場変更もこの関数だけ直せば十分です。
- ログ出力は“時刻+メッセージ”で追記。監査と失敗時の原因追跡が速くなります。
入口処理:ソース取り込みと整形(型変換・正規化)
取り込み・正規化テンプレ
' ModMonthly_ImportClean.bas
Option Explicit
Public Function ImportMonthlyCsv(ByVal csvPath As String) As Variant
Dim wb As Workbook, ws As Worksheet
Set wb = Application.Workbooks.Open(csvPath)
Set ws = wb.Worksheets(1)
ImportMonthlyCsv = ws.Range("A1").CurrentRegion.Value
wb.Close SaveChanges:=False
End Function
Public Function ToNumberOrZero(ByVal v As Variant) As Double
If IsNumeric(v) Then ToNumberOrZero = CDbl(v) Else ToNumberOrZero = 0#
End Function
Public Function ToDateOrEmpty(ByVal v As Variant) As Variant
If IsDate(v) Then ToDateOrEmpty = CDate(v) Else ToDateOrEmpty = ""
End Function
Public Function NormKey(ByVal v As Variant) As String
NormKey = LCase$(Trim$(CStr(v)))
End Function
Public Function CleanMonthly(ByVal a As Variant) As Variant
' 例の明細構成: A=注文日, B=顧客, C=商品, D=数量, E=金額
Dim out() As Variant: ReDim out(1 To UBound(a, 1), 1 To UBound(a, 2) + 1)
Dim lastCol As Long: lastCol = UBound(a, 2)
Dim r As Long, c As Long
For c = 1 To lastCol: out(1, c) = a(1, c): Next
out(1, lastCol + 1) = "YearMonth"
For r = 2 To UBound(a, 1)
For c = 1 To lastCol: out(r, c) = a(r, c): Next
out(r, 2) = NormKey(a(r, 2)) ' 顧客キー
out(r, 3) = NormKey(a(r, 3)) ' 商品キー
out(r, 4) = ToNumberOrZero(a(r, 4)) ' 数量
out(r, 5) = ToNumberOrZero(a(r, 5)) ' 金額
Dim dt As Variant: dt = ToDateOrEmpty(a(r, 1))
out(r, lastCol + 1) = IIf(IsDate(dt), Format(CDate(dt), "yyyy-mm"), "")
Next
CleanMonthly = out
End Function
VB重要部分の深掘り
- 数値・日付・キーの正規化は入口で徹底。ここで失敗は安全値(0・空)に落とし、集計の破綻を防ぎます。
- 年月派生列を付与すると、月次抽出がシンプルになり、ピボットの安定性も向上します。
集計とKPI:売上合計・件数・平均・達成率
グループ集計とKPI計算
' ModMonthly_Aggregate.bas
Option Explicit
Public Function FilterByYearMonth(ByVal a As Variant, ByVal ym As String) As Variant
' YearMonth列を最終列だと仮定
Dim ymCol As Long: ymCol = UBound(a, 2)
Dim r As Long, rows As Long: rows = 1
Dim out() As Variant: ReDim out(1 To 1, 1 To UBound(a, 2))
' ヘッダ
Dim c As Long: For c = 1 To UBound(a, 2): out(1, c) = a(1, c): Next
For r = 2 To UBound(a, 1)
If CStr(a(r, ymCol)) = ym Then
rows = rows + 1: ReDim Preserve out(1 To rows, 1 To UBound(a, 2))
For c = 1 To UBound(a, 2): out(rows, c) = a(r, c): Next
End If
Next
FilterByYearMonth = out
End Function
Public Function GroupSum(ByVal a As Variant, ByVal keyCol As Long, ByVal valCol As Long, ByVal hKey As String, ByVal hSum As String) As Variant
Dim d As Object: Set d = CreateObject("Scripting.Dictionary"): d.CompareMode = 1
Dim r As Long
For r = 2 To UBound(a, 1)
Dim k As String: k = CStr(a(r, keyCol))
Dim v As Double: v = ToNumberOrZero(a(r, valCol))
d(k) = IIf(d.Exists(k), d(k) + v, v)
Next
Dim out() As Variant: ReDim out(1 To d.Count + 1, 1 To 2)
out(1, 1) = hKey: out(1, 2) = hSum
Dim i As Long: i = 2, key As Variant
For Each key In d.Keys
out(i, 1) = key
out(i, 2) = d(key)
i = i + 1
Next
GroupSum = out
End Function
Public Function GroupCountAvg(ByVal a As Variant, ByVal keyCol As Long, ByVal valCol As Long, ByVal hKey As String) As Variant
Dim sumD As Object: Set sumD = CreateObject("Scripting.Dictionary"): sumD.CompareMode = 1
Dim cntD As Object: Set cntD = CreateObject("Scripting.Dictionary"): cntD.CompareMode = 1
Dim r As Long
For r = 2 To UBound(a, 1)
Dim k As String: k = CStr(a(r, keyCol))
Dim v As Double: v = ToNumberOrZero(a(r, valCol))
sumD(k) = IIf(sumD.Exists(k), sumD(k) + v, v)
cntD(k) = IIf(cntD.Exists(k), cntD(k) + 1, 1)
Next
Dim out() As Variant: ReDim out(1 To sumD.Count + 1, 1 To 4)
out(1, 1) = hKey: out(1, 2) = "Sum": out(1, 3) = "Count": out(1, 4) = "Avg"
Dim i As Long: i = 2, key As Variant
For Each key In sumD.Keys
out(i, 1) = key
out(i, 2) = sumD(key)
out(i, 3) = cntD(key)
out(i, 4) = IIf(cntD(key) > 0, sumD(key) / cntD(key), 0#)
i = i + 1
Next
GroupCountAvg = out
End Function
VB重要部分の深掘り
- 月次フィルタで対象月だけに絞ってから、顧客別や商品別の合計・件数・平均を出します。
- KPI(達成率や平均単価)は“分母ゼロ対策”が必須。0除算を避け、安定した値を返す設計にします。
レポートとピボット:見える化と更新の自動化
月次レポートの作成と書式
' ModMonthly_Report.bas
Option Explicit
Public Sub RenderMonthlyReport(ByVal monthData As Variant, ByVal outSheet As String)
Dim ws As Worksheet
On Error Resume Next: Set ws = Worksheets(outSheet): On Error GoTo 0
If ws Is Nothing Then Set ws = Worksheets.Add: ws.Name = outSheet Else ws.Cells.Clear
' 顧客別 金額合計・件数・平均
Dim custAgg As Variant: custAgg = GroupCountAvg(monthData, 2, 5, "Customer")
WriteBlock ws, custAgg, "A1"
' 商品別 金額合計
Dim prodSum As Variant: prodSum = GroupSum(monthData, 3, 5, "Product", "AmountSum")
WriteBlock ws, prodSum, "E1"
' 書式
With ws.Range("A1").CurrentRegion
.Columns.AutoFit: .Borders.LineStyle = xlContinuous
.Columns("B:D").NumberFormatLocal = "#,##0"
End With
With ws.Range("E1").CurrentRegion
.Columns.AutoFit: .Borders.LineStyle = xlContinuous
.Columns("F").NumberFormatLocal = "#,##0"
End With
End Sub
Public Sub WriteBlock(ByVal ws As Worksheet, ByVal a As Variant, ByVal startAddr As String)
ws.Range(startAddr).Resize(UBound(a, 1), UBound(a, 2)).Value = a
End Sub
VBピボット自動生成(商品×顧客の月次合計)
' ModMonthly_Pivot.bas
Option Explicit
Public Sub CreateMonthlyPivot(ByVal srcSheet As String, ByVal outSheet As String)
Dim wsSrc As Worksheet: Set wsSrc = Worksheets(srcSheet)
Dim srcRng As Range: Set srcRng = wsSrc.Range("A1").CurrentRegion
Dim wsOut As Worksheet
On Error Resume Next: Set wsOut = Worksheets(outSheet): On Error GoTo 0
If wsOut Is Nothing Then Set wsOut = Worksheets.Add: wsOut.Name = outSheet Else wsOut.Cells.Clear
Dim pc As PivotCache
Set pc = ActiveWorkbook.PivotCaches.Create(SourceType:=xlDatabase, SourceData:=srcRng)
Dim pt As PivotTable
Set pt = pc.CreatePivotTable(TableDestination:=wsOut.Range("A3"), TableName:="PivotMonthly")
With pt
.RowAxisLayout xlTabularRow
.PivotFields("商品").Orientation = xlRowField
.PivotFields("顧客").Orientation = xlColumnField
With .PivotFields("金額")
.Orientation = xlDataField
.Function = xlSum
.Name = "金額_合計"
.NumberFormat = "#,##0"
End With
End With
wsOut.Range("A1").Value = "月次ピボット(商品×顧客:金額合計)"
End Sub
VB重要部分の深掘り
- レポートは“配列→一括貼り→書式統一”。列の数値書式は“#,##0”に固定して視認性を確保します。
- ピボットは行・列・値を“フィールド名で指定”。列順が変わっても壊れません。タブ形式で見出し繰り返しを有効化します。
バックアップと締め処理:版管理・PDF/CSV出力
月次バックアップ・エクスポート
' ModMonthly_Archive.bas
Option Explicit
Public Sub BackupWorkbookMonthly(ByVal ym As String, ByVal backupRoot As String, Optional ByVal keep As Long = 12)
Dim folder As String: folder = backupRoot & "\Book"
If Not EnsureFolder(backupRoot) Or Not EnsureFolder(folder) Then Exit Sub
Dim path As String: path = folder & "\" & "Monthly_" & Replace(ym, "-", "") & ".xlsx"
Application.DisplayAlerts = False
ThisWorkbook.SaveCopyAs path
Application.DisplayAlerts = True
RotateByCount folder, ".xlsx", keep
End Sub
Private Sub RotateByCount(ByVal folder As String, ByVal ext As String, ByVal keep As Long)
Dim fso As Object: Set fso = CreateObject("Scripting.FileSystemObject")
Dim fl As Object: Set fl = fso.GetFolder(folder).Files
Dim list As New Collection, fi As Object
For Each fi In fl
If LCase$(Right$(fi.Name, Len(ext))) = LCase$(ext) Then list.Add fi
Next
If list.Count <= keep Then Exit Sub
' 作成日時で古い順に削除
Dim i As Long, j As Long, tmp As Object
For i = 1 To list.Count - 1
For j = i + 1 To list.Count
If list(i).DateCreated > list(j).DateCreated Then
Set tmp = list(i): Set list(i) = list(j): Set list(j) = tmp
End If
Next
Next
For i = 1 To list.Count - keep
On Error Resume Next: list(i).Delete True: On Error GoTo 0
Next
End Sub
Public Sub ExportMonthlyReport(ByVal ws As Worksheet, ByVal ym As String, ByVal outFolder As String)
If Not EnsureFolder(outFolder) Then Exit Sub
Dim csvPath As String: csvPath = outFolder & "\report_" & Replace(ym, "-", "") & ".csv"
Dim pdfPath As String: pdfPath = outFolder & "\report_" & Replace(ym, "-", "") & ".pdf"
' CSV
Dim tempWB As Workbook: Set tempWB = Application.Workbooks.Add
ws.Range("A1").CurrentRegion.Copy
tempWB.Worksheets(1).Range("A1").PasteSpecial xlPasteValues
Application.DisplayAlerts = False
tempWB.SaveAs Filename:=csvPath, FileFormat:=xlCSVUTF8
Application.DisplayAlerts = True
tempWB.Close False
' PDF
With ws.PageSetup
.Orientation = xlPortrait: .Zoom = False
.FitToPagesWide = 1: .FitToPagesTall = 1
.LeftMargin = Application.CentimetersToPoints(1)
.RightMargin = Application.CentimetersToPoints(1)
.TopMargin = Application.CentimetersToPoints(1)
.BottomMargin = Application.CentimetersToPoints(1)
End With
ws.ExportAsFixedFormat Type:=xlTypePDF, Filename:=pdfPath, Quality:=xlQualityStandard, OpenAfterPublish:=False
End Sub
VB重要部分の深掘り
- 月次バックアップは“年月でファイル名固定+12世代保持”が定番。年単位でローテーションすると運用が楽です。
- CSVは“値貼り付け+UTF-8”、PDFは印刷設定をコードで固定。毎月同じ見た目を保ちます。
月次パイプライン例:対象月指定→取り込み→整形→集計→レポート→ピボット→バックアップ
一括実行テンプレ(貼って動く)
' ModMonthly_Pipeline.bas
Option Explicit
Public Sub Run_MonthlyProcess(ByVal year As Long, ByVal month As Long)
Dim cfg As MonthlyConfig: cfg = LoadMonthlyConfig(year, month)
If Not EnsureFolder(cfg.SrcFolder) Or Not EnsureFolder(cfg.OutFolder) Or Not EnsureFolder(cfg.BackupFolder) Then
MsgBox "フォルダ準備に失敗しました。", vbExclamation: Exit Sub
End If
Dim logPath As String: logPath = cfg.BackupFolder & "\monthly_" & Replace(cfg.YearMonth, "-", "") & ".log"
On Error GoTo FAIL
AppendLog logPath, "START: " & cfg.YearMonth
' 1) 入口:CSV取り込み
Dim csvPath As String: csvPath = cfg.SrcFolder & "\detail_" & Replace(cfg.YearMonth, "-", "") & ".csv"
AppendLog logPath, "IMPORT: " & csvPath
Dim raw As Variant: raw = ImportMonthlyCsv(csvPath)
' 2) 整形
AppendLog logPath, "CLEAN"
Dim cleaned As Variant: cleaned = CleanMonthly(raw)
' 3) 月次抽出
AppendLog logPath, "FILTER"
Dim monthData As Variant: monthData = FilterByYearMonth(cleaned, cfg.YearMonth)
' 4) レポート出力
AppendLog logPath, "REPORT"
RenderMonthlyReport monthData, "Monthly_Report"
' 5) ピボット作成
AppendLog logPath, "PIVOT"
CreateMonthlyPivot "Monthly_Report", "Monthly_Pivot"
' 6) エクスポート
AppendLog logPath, "EXPORT"
ExportMonthlyReport Worksheets("Monthly_Report"), cfg.YearMonth, cfg.OutFolder
' 7) バックアップ
AppendLog logPath, "BACKUP"
BackupWorkbookMonthly cfg.YearMonth, cfg.BackupFolder, 12
AppendLog logPath, "OK"
MsgBox "月次処理(" & cfg.YearMonth & ")が完了しました。", vbInformation
Exit Sub
FAIL:
AppendLog logPath, "FAILED: " & Err.Number & " - " & Err.Description
MsgBox "月次処理でエラーが発生しました(ログ参照)", vbExclamation
End Sub
VB期待動作の確認ポイント
- 対象月のCSVが取り込まれ、正規化・月次抽出の後に顧客/商品別のレポートが生成。
- ピボットが作られ、CSV/PDFが出力され、12世代のバックアップが管理されます。
- ログに各工程の開始・成功が記録され、失敗時は内容が残ります。
落とし穴と対策(深掘り)
年月の指定ミスやファイル欠損
“detail_yyyymm.csv”命名規則を固定し、存在しない場合は直ちにログ記録して停止します。次工程へ進めないのが安全です。
文字数値・テキスト日付で平均・合計が崩れる
入口で ToNumberOrZero/ToDateOrEmpty を通し、失敗は安全値へ落とす設計を徹底します。
グループ列の揺らぎで月次抽出漏れ
YearMonthは明細内で派生・固定。文字列“yyyy-mm”で持つと比較が安定し、ピボット列にも使いやすいです。
出力書式のふらつき
数値書式“#,##0”と罫線・AutoFitを標準化して適用。レビュー性が飛躍的に上がります。
版管理の誤削除
12世代保持のローテーションは作成日時で厳格に制御。初期は保持数を多めに設定して運用の癖を掴みます。
まとめ:期間キー→正規化→集計→見える化→バックアップの型で、月次を“同じ品質”にする
対象月をキーで決め、入口で揺らぎを潰し、顧客・商品のKPIを一撃で作成。ピボットと書式で見える化し、CSV・PDF・バックアップまで自動化すれば、毎月の締めが短時間で、再現性高く行えます。
