グループ集計
「部署ごと」「商品ごと」「年月ごと」などのグループ単位で、合計・件数・平均をまとめる定番テンプレを、初心者でも壊れず使える形で整理しました。少量なら関数、柔軟・大量なら配列+辞書、見た目重視ならピボットが最短です。
選び方の指針
- 最短・少量: SUMIFS/COUNTIFS/AVERAGEIFS を「キー別」に回す
- 大量・柔軟: 配列→辞書で「キー→指標」を一括集計(爆速)
- 見た目で確認しながら: ピボットテーブルで即表化・更新
- 列順が変わる現場: 見出し名から列番号を取得して安全に処理
基本:関数でグループ集計(部署リストに対して合計・件数・平均)
Sub GroupSummary_WithFunctions()
'明細:A=部署, B=日付, C=金額
Dim depR As Range, dateR As Range, amtR As Range
Set depR = Range("A2:A100000")
Set dateR = Range("B2:B100000")
Set amtR = Range("C2:C100000")
'部署リスト:F列に部署が並ぶ(F2〜)
Dim lastOut As Long: lastOut = Cells(Rows.Count, "F").End(xlUp).Row
Dim r As Long, dept As String
For r = 2 To lastOut
dept = Cells(r, "F").Value
'合計
Cells(r, "G").Value = Application.WorksheetFunction.SumIfs(amtR, depR, dept)
'件数
Cells(r, "H").Value = Application.WorksheetFunction.CountIfs(depR, dept)
'平均(0件時のエラーを回避)
On Error Resume Next
Cells(r, "I").Value = Application.WorksheetFunction.AverageIfs(amtR, depR, dept)
On Error GoTo 0
Next
End Sub
VB- ポイント
- 期間で絞る: dateR に「>=開始」「<翌日」など追加すれば月次・年次なども対応可能。
- OR条件(部署が複数): 値ごとに関数を回して足し合わせるか、辞書集計へ切り替える。
爆速:辞書で「キー→合計・件数・平均」を一括(大量行向け)
Sub GroupSummary_Dictionary()
'明細:A=キー(部署など), B=日付, C=金額
Dim rg As Range: Set rg = Range("A1").CurrentRegion
Dim v As Variant: v = rg.Value
'辞書を用意(合計・件数)
Dim sumMap As Object: Set sumMap = CreateObject("Scripting.Dictionary")
Dim cntMap As Object: Set cntMap = CreateObject("Scripting.Dictionary")
Dim i As Long, key As String, amt As Double
For i = 2 To UBound(v, 1)
key = Trim$(UCase$(CStr(v(i, 1)))) 'キー正規化(表記揺れ対策)
amt = Val(v(i, 3))
If sumMap.Exists(key) Then
sumMap(key) = sumMap(key) + amt
cntMap(key) = cntMap(key) + 1
Else
sumMap.Add key, amt
cntMap.Add key, 1
End If
Next
'出力:F=キー, G=合計, H=件数, I=平均
Dim keys As Variant: keys = sumMap.Keys
Dim n As Long: n = UBound(keys) + 1
If n > 0 Then
Dim out() As Variant: ReDim out(1 To n, 1 To 4)
For i = 0 To UBound(keys)
out(i + 1, 1) = keys(i)
out(i + 1, 2) = sumMap(keys(i))
out(i + 1, 3) = cntMap(keys(i))
out(i + 1, 4) = sumMap(keys(i)) / cntMap(keys(i))
Next
With Worksheets("集計")
.Range("F1:I1").Value = Array("キー", "合計", "件数", "平均")
.Range("F2").Resize(n, 4).Value = out
End With
End If
End Sub
VB- ポイント
- 爆速の基本形: 範囲→配列→辞書→一括書き戻し。セル往復をなくす。
- 軸追加: キーを「部署|yyyymm」など連結すれば「部署×年月」も一撃。
見出し名で列特定して安全にグループ集計(列順変更に強い)
Sub GroupSummary_ByHeaders()
Dim rg As Range: Set rg = Range("A1").CurrentRegion
Dim head As Range: Set head = rg.Rows(1)
Dim cKey As Long: cKey = FindHeader(head, "部署") 'キー列名
Dim cAmt As Long: cAmt = FindHeader(head, "金額") '集計対象
If cKey * cAmt = 0 Then MsgBox "見出しが見つかりません": Exit Sub
Dim v As Variant: v = rg.Value
Dim sumMap As Object: Set sumMap = CreateObject("Scripting.Dictionary")
Dim cntMap As Object: Set cntMap = CreateObject("Scripting.Dictionary")
Dim i As Long, key As String
For i = 2 To UBound(v, 1)
key = Trim$(UCase$(CStr(v(i, cKey))))
If sumMap.Exists(key) Then
sumMap(key) = sumMap(key) + Val(v(i, cAmt))
cntMap(key) = cntMap(key) + 1
Else
sumMap.Add key, Val(v(i, cAmt))
cntMap.Add key, 1
End If
Next
Dim rOut As Long: rOut = 2, k As Variant
With Worksheets("集計")
.Range("F1:I1").Value = Array("部署", "合計", "件数", "平均")
For Each k In sumMap.Keys
.Cells(rOut, "F").Value = k
.Cells(rOut, "G").Value = sumMap(k)
.Cells(rOut, "H").Value = cntMap(k)
.Cells(rOut, "I").Value = sumMap(k) / cntMap(k)
rOut = rOut + 1
Next
End With
End Sub
Private Function FindHeader(ByVal headerRow As Range, ByVal name As String) As Long
Dim hit As Range
Set hit = headerRow.Find(What:=name, LookAt:=xlWhole, LookIn:=xlValues, MatchCase:=False)
FindHeader = IIf(hit Is Nothing, 0, hit.Column)
End Function
VB- ポイント
- 列順変更耐性: 見出し名で列探索、壊れない運用に。
- 出力列名を揃える: 集計表のヘッダーは最初に書いておくと見やすい。
ピボットテーブルでグループ集計を瞬時に表へ
Sub GroupSummary_Pivot()
Dim src As Range: Set src = Range("A1").CurrentRegion 'A=部署, B=日付, C=金額
Dim pc As PivotCache, pt As PivotTable
Dim outWs As Worksheet
On Error Resume Next
Set outWs = Worksheets("ピボット")
If outWs Is Nothing Then
Set outWs = Worksheets.Add: outWs.Name = "ピボット"
End If
On Error GoTo 0
Set pc = ActiveWorkbook.PivotCaches.Create(xlDatabase, src)
Set pt = pc.CreatePivotTable(outWs.Range("A3"), "グループ集計PT")
With pt
.PivotFields("部署").Orientation = xlRowField
With .PivotFields("金額")
.Orientation = xlDataField
.Function = xlSum
.NumberFormat = "#,##0"
End With
'必要なら列やフィルタ軸を追加
'.PivotFields("日付").Orientation = xlColumnField
'.PivotFields("日付").NumberFormat = "yyyy-mm"
End With
End Sub
VB- ポイント
- 見た目が強い: すぐ表になる。更新は
PivotCache.Refreshで一瞬。 - 複数指標: 同じ「金額」フィールドを件数・平均に切り替えて追加も可能。
- 見た目が強い: すぐ表になる。更新は
よくある落とし穴と対策
- ラベル揺れで別集計になる
- 対策: キーは
Trim/UCaseで正規化。必要なら半角化や余分な記号の置換も事前対応。
- 対策: キーは
- 数値が文字列で集計されない
- 対策:
Valで安全に数値化。集計前に.Value = .Valueで値化して式を外す。
- 対策:
- 期間や複数軸で集計したい
- 対策: 辞書キーを「部署|yyyymm」など連結して多軸化。ピボットなら行×列×値で即対応。
- セル往復で遅い
- 対策: 範囲→配列→辞書→一括書き戻し。結果を配列にまとめて貼る。
例題で練習
'例1:部署リスト(F列)に対して合計・件数・平均(関数)
Sub Example_FunctionsGroup()
Call GroupSummary_WithFunctions
End Sub
'例2:辞書で部署別の合計・件数・平均を爆速出力
Sub Example_DictGroup()
Call GroupSummary_Dictionary
End Sub
'例3:見出し名で列を特定して安全にグループ集計
Sub Example_ByHeadersGroup()
Call GroupSummary_ByHeaders
End Sub
'例4:ピボットテーブルでグループ集計を一発作成
Sub Example_PivotGroup()
Call GroupSummary_Pivot
End Sub
VB