UNIQUE+集計セット
重複をユニーク化したあとに、合計・件数・最大/最小・最新などを一気にまとめる“鉄板テンプレ”です。ピボット不要で、辞書+配列だけ。初心者向けに丁寧にかみ砕いて説明します。
使う場面のパターン
- 基本集計: コードごとに数量合計・売上合計・件数。
- 最新抽出: コードごとに最新日付の単価・ステータス。
- 複合キー: コード×月で月次集計(件数・合計・平均)。
- 安全出力: 元表は触らず、別シートへユニーク+集計を出す。
共通ユーティリティ(速度・正規化)
Option Explicit
Private Sub SpeedOn()
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual
End Sub
Private Sub SpeedOff()
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
Private Function NormKey(ByVal v As Variant) As String
NormKey = UCase$(Trim$(CStr(v)))
End Function
Private Function NormDate(ByVal v As Variant) As Date
If IsDate(v) Then NormDate = CDate(v) Else NormDate = 0
End Function
Private Function EnsureSheet(ByVal name As String, Optional ByVal clear As Boolean = True) As Worksheet
Dim ws As Worksheet
On Error Resume Next
Set ws = Worksheets(name)
On Error GoTo 0
If ws Is Nothing Then
Set ws = Worksheets.Add(After:=Worksheets(Worksheets.Count))
ws.Name = name
End If
If clear Then ws.Cells.Clear
Set EnsureSheet = ws
End Function
VB- ポイント
- 速度最適化: 画面更新・イベント・計算を止める。
- キー正規化: Trim+大文字化で表記揺れ対策。
- 日付変換:
NormDateで安全にDateへ。
基本テンプレ:コードごとにUNIQUE+集計(合計・件数・最新)
入力「Data」シート例(見出しあり):A=コード、B=日付、C=数量、D=単価。
出力「集計」シート:コードごとに数量合計、売上合計、件数、最新日付の単価。
Sub UniqueAggregate_Basic()
SpeedOn
Dim ws As Worksheet: Set ws = Worksheets("Data")
Dim rg As Range: Set rg = ws.Range("A1").CurrentRegion
Dim v As Variant: v = rg.Value
'列インデックス(必要ならFindで見出し検索に変更可能)
Dim cCode As Long: cCode = 1
Dim cDate As Long: cDate = 2
Dim cQty As Long: cQty = 3
Dim cPrice As Long: cPrice = 4
'グループ辞書
Dim sumQty As Object: Set sumQty = CreateObject("Scripting.Dictionary")
Dim sumSales As Object: Set sumSales = CreateObject("Scripting.Dictionary")
Dim cnt As Object: Set cnt = CreateObject("Scripting.Dictionary")
Dim latestDate As Object: Set latestDate = CreateObject("Scripting.Dictionary")
Dim latestPrice As Object: Set latestPrice = CreateObject("Scripting.Dictionary")
Dim r As Long, k As String, d As Date
For r = 2 To UBound(v, 1)
k = NormKey(v(r, cCode))
If Len(k) = 0 Then GoTo cont
d = NormDate(v(r, cDate))
'集計(初期値は0扱い)
sumQty(k) = CDbl(Val(sumQty(k))) + CDbl(Val(v(r, cQty)))
sumSales(k) = CDbl(Val(sumSales(k))) + CDbl(Val(v(r, cQty))) * CDbl(Val(v(r, cPrice)))
cnt(k) = CLng(Val(cnt(k))) + 1
'最新日付の単価を保持
If d > 0 Then
If Not latestDate.Exists(k) Or d > latestDate(k) Then
latestDate(k) = d
latestPrice(k) = CDbl(Val(v(r, cPrice)))
End If
End If
cont:
Next
'出力
Dim out As Worksheet: Set out = EnsureSheet("集計", True)
out.Range("A1:F1").Value = Array("コード", "数量合計", "売上合計", "件数", "最新日付", "最新単価")
Dim i As Long: i = 2
Dim key As Variant
For Each key In sumQty.Keys
out.Cells(i, 1).Value = key
out.Cells(i, 2).Value = sumQty(key)
out.Cells(i, 3).Value = sumSales(key)
out.Cells(i, 4).Value = cnt(key)
If latestDate.Exists(key) Then
out.Cells(i, 5).Value = latestDate(key)
out.Cells(i, 5).NumberFormatLocal = "yyyy/mm/dd"
out.Cells(i, 6).Value = latestPrice(key)
End If
i = i + 1
Next
out.Columns.AutoFit
SpeedOff
MsgBox "UNIQUE+集計(基本)完了: " & i - 2 & "コード"
End Sub
VB- ポイント
- UNIQUE化は辞書のKeysが自然に担います。
- 売上合計: 数量×単価を積み上げ。
- 最新: 日付比較で最大の日の単価採用。
複合キー:コード×月でUNIQUE+月次集計(件数・合計・平均)
A=コード、B=日付、C=数量、D=金額(数量×単価でもOK)。
出力は「コード×yyyy-mm」のユニークキーで件数、合計数量、合計金額、平均単価(合計金額/合計数量)。
Sub UniqueAggregate_MonthlyComposite()
SpeedOn
Dim v As Variant: v = Worksheets("Data").Range("A1").CurrentRegion.Value
Dim cCode As Long: cCode = 1
Dim cDate As Long: cDate = 2
Dim cQty As Long: cQty = 3
Dim cAmt As Long: cAmt = 4
'複合キー辞書(code|yyyy-mm)
Dim sumQty As Object: Set sumQty = CreateObject("Scripting.Dictionary")
Dim sumAmt As Object: Set sumAmt = CreateObject("Scripting.Dictionary")
Dim cnt As Object: Set cnt = CreateObject("Scripting.Dictionary")
Dim r As Long, code As String, d As Date, ym As String, key As String
For r = 2 To UBound(v, 1)
code = NormKey(v(r, cCode))
d = NormDate(v(r, cDate))
If Len(code) = 0 Or d = 0 Then GoTo cont
ym = Format$(d, "yyyy-mm")
key = code & "|" & ym
sumQty(key) = CDbl(Val(sumQty(key))) + CDbl(Val(v(r, cQty)))
sumAmt(key) = CDbl(Val(sumAmt(key))) + CDbl(Val(v(r, cAmt)))
cnt(key) = CLng(Val(cnt(key))) + 1
cont:
Next
Dim out As Worksheet: Set out = EnsureSheet("月次集計", True)
out.Range("A1:F1").Value = Array("コード", "年月", "件数", "数量合計", "金額合計", "平均単価")
Dim i As Long: i = 2
Dim k As Variant
For Each k In sumQty.Keys
Dim parts() As String: parts = Split(CStr(k), "|")
out.Cells(i, 1).Value = parts(0)
out.Cells(i, 2).Value = parts(1)
out.Cells(i, 3).Value = cnt(k)
out.Cells(i, 4).Value = sumQty(k)
out.Cells(i, 5).Value = sumAmt(k)
If sumQty(k) <> 0 Then out.Cells(i, 6).Value = sumAmt(k) / sumQty(k)
i = i + 1
Next
out.Columns.AutoFit
SpeedOff
MsgBox "UNIQUE+月次集計完了: " & i - 2 & "グループ"
End Sub
VB- ポイント
- 複合キー: 区切りに「|」を使うと安全。
- 平均単価: 金額合計/数量合計。
高速カスタム集計:合計・最大・最小・最新を一度に
要件が増えても一度に処理する“拡張セット”。A=コード、B=日付、C=数量、D=単価。
Sub UniqueAggregate_AdvancedSet()
SpeedOn
Dim v As Variant: v = Worksheets("Data").Range("A1").CurrentRegion.Value
Dim cCode As Long: cCode = 1
Dim cDate As Long: cDate = 2
Dim cQty As Long: cQty = 3
Dim cPrice As Long: cPrice = 4
Dim sumQty As Object: Set sumQty = CreateObject("Scripting.Dictionary")
Dim maxPrice As Object: Set maxPrice = CreateObject("Scripting.Dictionary")
Dim minPrice As Object: Set minPrice = CreateObject("Scripting.Dictionary")
Dim latestDate As Object: Set latestDate = CreateObject("Scripting.Dictionary")
Dim latestPrice As Object: Set latestPrice = CreateObject("Scripting.Dictionary")
Dim cnt As Object: Set cnt = CreateObject("Scripting.Dictionary")
Dim r As Long, k As String, d As Date, q As Double, p As Double
For r = 2 To UBound(v, 1)
k = NormKey(v(r, cCode))
If Len(k) = 0 Then GoTo cont
d = NormDate(v(r, cDate))
q = CDbl(Val(v(r, cQty)))
p = CDbl(Val(v(r, cPrice)))
sumQty(k) = CDbl(Val(sumQty(k))) + q
cnt(k) = CLng(Val(cnt(k))) + 1
If Not maxPrice.Exists(k) Or p > maxPrice(k) Then maxPrice(k) = p
If Not minPrice.Exists(k) Or p < minPrice(k) Then minPrice(k) = p
If d > 0 Then
If Not latestDate.Exists(k) Or d > latestDate(k) Then
latestDate(k) = d
latestPrice(k) = p
End If
End If
cont:
Next
Dim out As Worksheet: Set out = EnsureSheet("拡張集計", True)
out.Range("A1:G1").Value = Array("コード", "件数", "数量合計", "最大単価", "最小単価", "最新日付", "最新単価")
Dim i As Long: i = 2
Dim key As Variant
For Each key In cnt.Keys
out.Cells(i, 1).Value = key
out.Cells(i, 2).Value = cnt(key)
out.Cells(i, 3).Value = sumQty(key)
out.Cells(i, 4).Value = maxPrice(key)
out.Cells(i, 5).Value = minPrice(key)
If latestDate.Exists(key) Then
out.Cells(i, 6).Value = latestDate(key)
out.Cells(i, 6).NumberFormatLocal = "yyyy/mm/dd"
out.Cells(i, 7).Value = latestPrice(key)
End If
i = i + 1
Next
out.Columns.AutoFit
SpeedOff
MsgBox "UNIQUE+拡張集計完了: " & i - 2 & "コード"
End Sub
VB- ポイント
- 一括集計: 計算をループ内で全て済ませるので速い。
- 初期値管理:
Existsで初回代入→以降更新。
例題と運用のコツ
- 例題1(基本集計): コードごとに数量合計・売上合計・最新単価
- 実行:
UniqueAggregate_Basic
- 実行:
- 例題2(月次集計): コード×月の件数・合計・平均単価
- 実行:
UniqueAggregate_MonthlyComposite
- 実行:
- 例題3(拡張セット): 合計・最大/最小・最新の一括出力
- 実行:
UniqueAggregate_AdvancedSet
- 実行:
- コツ
- キーの正規化は必須: 前後空白・大小文字で別物扱いを防ぐ。
- 日付統一:
CDateでDate型にしてからFormatは出力で行う。 - 元表を触らない: 常に別シートへ出力すると安全。
- 列特定を堅く: 実務では見出し名から列番号を取得(
Find)に置き換えると壊れない。
