重複行を1行にまとめる
「同じキーが複数行に分かれているので、1行にまとめたい」——集計やレポートでよく出る要望です。初心者でも安心して使えるように、基本の考え方からコード例、応用までかみ砕いて説明します。
基本の考え方
- キー列: 「同じ」と判定する基準(例:コード)。
- まとめ方:
- 数値列は合計・平均などにまとめる。
- 文字列列は結合して1セルにまとめる。
- 出力: 元表は壊さず、別シートに「まとめ済み一覧」を作る。
共通ユーティリティ(速度・正規化・出力)
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 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テンプレ1:数値列を合計して1行にまとめる
入力例:「Data」シートに A=コード、B=商品名、C=数量、D=金額。
出力:「まとめ」シートにコードごとに数量合計・金額合計を1行にまとめる。
Sub MergeDuplicateRows_Sum()
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
Dim dictQty As Object: Set dictQty = CreateObject("Scripting.Dictionary")
Dim dictAmt As Object: Set dictAmt = CreateObject("Scripting.Dictionary")
Dim dictName As Object: Set dictName = CreateObject("Scripting.Dictionary")
Dim r As Long, k As String
For r = 2 To UBound(v, 1)
k = NormKey(v(r, 1)) ' コード
If Len(k) = 0 Then GoTo cont
dictQty(k) = CDbl(Val(dictQty(k))) + CDbl(Val(v(r, 3)))
dictAmt(k) = CDbl(Val(dictAmt(k))) + CDbl(Val(v(r, 4)))
If Not dictName.Exists(k) Then dictName(k) = v(r, 2)
cont:
Next
Dim out As Worksheet: Set out = EnsureSheet("まとめ", True)
out.Range("A1:D1").Value = Array("コード", "商品名", "数量合計", "金額合計")
Dim i As Long: i = 2
Dim key As Variant
For Each key In dictQty.Keys
out.Cells(i, 1).Value = key
out.Cells(i, 2).Value = dictName(key)
out.Cells(i, 3).Value = dictQty(key)
out.Cells(i, 4).Value = dictAmt(key)
i = i + 1
Next
out.Columns.AutoFit
SpeedOff
MsgBox "重複行をまとめました。件数: " & i - 2
End Sub
VB- ポイント: 同じコードの数量・金額を合計して1行に。
テンプレ2:文字列列を結合して1行にまとめる
入力例:A=コード、B=担当者。
出力:コードごとに担当者を「,」区切りでまとめる。
Sub MergeDuplicateRows_Concat()
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
Dim dictConcat As Object: Set dictConcat = CreateObject("Scripting.Dictionary")
Dim r As Long, k As String
For r = 2 To UBound(v, 1)
k = NormKey(v(r, 1)) ' コード
If Len(k) = 0 Then GoTo cont
If dictConcat.Exists(k) Then
dictConcat(k) = dictConcat(k) & "," & v(r, 2)
Else
dictConcat(k) = v(r, 2)
End If
cont:
Next
Dim out As Worksheet: Set out = EnsureSheet("まとめ文字列", True)
out.Range("A1:B1").Value = Array("コード", "担当者一覧")
Dim i As Long: i = 2
Dim key As Variant
For Each key In dictConcat.Keys
out.Cells(i, 1).Value = key
out.Cells(i, 2).Value = dictConcat(key)
i = i + 1
Next
out.Columns.AutoFit
SpeedOff
MsgBox "文字列列を結合してまとめました。件数: " & i - 2
End Sub
VB- ポイント: 同じコードの担当者を「A,B,C」と1セルにまとめる。
テンプレ3:最新日付の行だけ残す(古い行はまとめない)
入力例:A=コード、B=日付、C=数量。
出力:コードごとに最新日付の行だけ残す。
Sub MergeDuplicateRows_KeepLatest()
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
Dim latestDate As Object: Set latestDate = CreateObject("Scripting.Dictionary")
Dim latestRow As Object: Set latestRow = CreateObject("Scripting.Dictionary")
Dim r As Long, k As String, d As Date
For r = 2 To UBound(v, 1)
k = NormKey(v(r, 1))
If Len(k) = 0 Or Not IsDate(v(r, 2)) Then GoTo cont
d = CDate(v(r, 2))
If Not latestDate.Exists(k) Or d > latestDate(k) Then
latestDate(k) = d
latestRow(k) = r
End If
cont:
Next
Dim out As Worksheet: Set out = EnsureSheet("まとめ最新", True)
out.Range("A1:C1").Value = Array("コード", "最新日付", "数量")
Dim i As Long: i = 2
Dim key As Variant
For Each key In latestRow.Keys
out.Cells(i, 1).Value = v(latestRow(key), 1)
out.Cells(i, 2).Value = v(latestRow(key), 2)
out.Cells(i, 3).Value = v(latestRow(key), 3)
i = i + 1
Next
out.Columns.AutoFit
SpeedOff
MsgBox "最新日付の行だけ残しました。件数: " & i - 2
End Sub
VB- ポイント: 最新日付だけ残すので「まとめ」というより“抽出”に近い。
例題で練習
'例1:コードごとに数量・金額を合計して1行にまとめる
Sub Example_Sum()
MergeDuplicateRows_Sum
End Sub
'例2:コードごとに担当者を結合して1行にまとめる
Sub Example_Concat()
MergeDuplicateRows_Concat
End Sub
'例3:コードごとに最新日付の行だけ残す
Sub Example_KeepLatest()
MergeDuplicateRows_KeepLatest
End Sub
VB初心者向けポイント
- まずは別シート出力: 元表を壊さないので安心。
- キー正規化: 空白や大小文字の違いで別物扱いにならないように。
- まとめ方を決める: 数値は合計/文字列は結合/日付は最新など、ルールを明確に。
- 削除は下から: 実際に元表を削除する場合は必ず「下から」処理。
