2列以上の重複
「コード×日付」「部門×担当者」など、複数列の組み合わせで“同じ”かどうかを判定して、見える化・一覧出力・削除候補・安全削除までを一気にまとめました。初心者向けに、貼ってすぐ使えるテンプレです。
基本の考え方
- 複合キー: 対象列を連結して一意のキーにする(例: 「コード|yyyy-mm-dd」)。
- 正規化: 前後空白、大小文字、日付フォーマットをそろえると誤判定が減る。
- 安全運用: まずは一覧化→色で確認→承認→下から削除。
共通ユーティリティ(速度・正規化・出力)
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 NormText(ByVal v As Variant) As String
NormText = UCase$(Trim$(CStr(v)))
End Function
Private Function NormDateText(ByVal v As Variant) As String
If IsDate(v) Then
NormDateText = Format$(CDate(v), "yyyy-mm-dd")
Else
NormDateText = UCase$(Trim$(CStr(v)))
End If
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- ポイント: 速度最適化はON/OFFがセット。日付はyyyy-mm-ddに統一。
複合キーの作り方(2列・3列)
'2列複合キー:コード×日付
Private Function Key2(ByVal v1 As Variant, ByVal v2 As Variant) As String
Key2 = NormText(v1) & "|" & NormDateText(v2)
End Function
'3列複合キー:部門×コード×枝番
Private Function Key3(ByVal v1 As Variant, ByVal v2 As Variant, ByVal v3 As Variant) As String
Key3 = NormText(v1) & "|" & NormText(v2) & "|" & NormText(v3)
End Function
VB- 区切り文字: 「|」が安全。値内で使われにくく誤分割が起きにくい。
2列以上の重複を一覧出力(候補抽出)
「Data」シートで、A=コード、B=日付を例に、重複キーの行番号を一覧化します。
Sub ListDuplicates_TwoColumns()
SpeedOn
Dim ws As Worksheet: Set ws = Worksheets("Data")
Dim lastRow As Long: lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Dim seen As Object: Set seen = CreateObject("Scripting.Dictionary")
Dim pos As Object: Set pos = CreateObject("Scripting.Dictionary")
Dim r As Long, k As String
For r = 2 To lastRow
k = Key2(ws.Cells(r, "A").Value, ws.Cells(r, "B").Value)
If InStr(k, "|") = 0 Then GoTo cont ' どちらか空ならスキップ
If seen.Exists(k) Then
pos(k) = pos(k) & "," & r
Else
seen(k) = True
pos(k) = CStr(r)
End If
cont:
Next
Dim out As Worksheet: Set out = EnsureSheet("重複一覧(2列)", True)
out.Range("A1:D1").Value = Array("コード", "日付", "出現回数", "行番号一覧")
Dim i As Long: i = 2
Dim key As Variant
For Each key In pos.Keys
Dim arrPos() As String: arrPos = Split(pos(key), ",")
If UBound(arrPos) >= 1 Then
Dim parts() As String: parts = Split(CStr(key), "|")
out.Cells(i, 1).Value = parts(0)
out.Cells(i, 2).Value = parts(1)
out.Cells(i, 3).Value = UBound(arrPos) + 1
out.Cells(i, 4).Value = pos(key)
i = i + 1
End If
Next
out.Columns.AutoFit
SpeedOff
MsgBox "2列以上の重複一覧を作成しました(件数: " & i - 2 & ")"
End Sub
VB- 使い方: 候補一覧で確認→承認後に削除へ進めると安全。
3列複合キーの重複をハイライト
「部門×コード×枝番」で重複行を淡黄色に塗ります。
Sub HighlightDuplicates_ThreeColumns()
SpeedOn
Dim ws As Worksheet: Set ws = Worksheets("Data")
Dim lastRow As Long: lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
ws.Range("A2:C" & lastRow).Interior.ColorIndex = xlNone
Dim seen As Object: Set seen = CreateObject("Scripting.Dictionary")
Dim r As Long, k As String
For r = 2 To lastRow
k = Key3(ws.Cells(r, "A").Value, ws.Cells(r, "B").Value, ws.Cells(r, "C").Value)
If InStr(k, "|") = 0 Then GoTo cont
If seen.Exists(k) Then
ws.Range("A" & r & ":C" & r).Interior.Color = RGB(255, 245, 180)
Dim firstRow As Long: firstRow = CLng(Split(seen(k), "|")(0)) '初回行番号も塗る(任意)
ws.Range("A" & firstRow & ":C" & firstRow).Interior.Color = RGB(255, 245, 180)
Else
seen(k) = r & "|" '初回行保持
End If
cont:
Next
SpeedOff
MsgBox "3列複合キーの重複をハイライトしました"
End Sub
VB- 見える化: 削除前に“どこが重複か”を現場で合意しやすい。
重複の安全削除(2列以上、先頭を残す)
一覧化せずに、2列キーで“2回目以降”を削除します。必ず“下から”削除。
Sub RemoveDuplicates_TwoColumns_Safe()
SpeedOn
Dim ws As Worksheet: Set ws = Worksheets("Data")
Dim lastRow As Long: lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Dim seen As Object: Set seen = CreateObject("Scripting.Dictionary")
Dim delRows As Collection: Set delRows = New Collection
Dim r As Long, k As String
For r = 2 To lastRow
k = Key2(ws.Cells(r, "A").Value, ws.Cells(r, "B").Value)
If InStr(k, "|") = 0 Then GoTo cont
If seen.Exists(k) Then
delRows.Add r
Else
seen(k) = True
End If
cont:
Next
Dim i As Long
For i = delRows.Count To 1 Step -1
ws.Rows(delRows(i)).Delete
Next
SpeedOff
MsgBox "2列複合キーの重複削除完了: " & delRows.Count & "行(先頭を残す)"
End Sub
VB- 鉄則: 上から削除は行ズレの原因。必ず“下から”。
標準機能で一撃(RemoveDuplicates:複数列)
見出しありの表なら、標準機能でも複数列重複の削除が可能です。
Sub RemoveDuplicates_BuiltIn_Multi()
SpeedOn
With Worksheets("Data").Range("A1").CurrentRegion
' A列とB列を複合キーとして重複削除(先にある行を残す)
.RemoveDuplicates Columns:=Array(1, 2), Header:=xlYes
End With
SpeedOff
MsgBox "標準機能で複数列の重複を削除しました(先頭を残す)"
End Sub
VB- メリット: 超簡単・超高速。列が確定しているならこれが最短。
- 注意: “先頭を残す”挙動。最新優先などのルールは別テンプレで。
区分ごとに複数列重複を処理(部門ごとにコード×日付)
「部門ごとにコード×日付の重複を除去(先頭を残す)」の例です。
Sub RemoveDuplicates_ByGroup_MultiKey()
SpeedOn
Dim ws As Worksheet: Set ws = Worksheets("Data")
Dim lastRow As Long: lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Dim seen As Object: Set seen = CreateObject("Scripting.Dictionary")
Dim delRows As Collection: Set delRows = New Collection
Dim r As Long, grp As String, k As String, comp As String
For r = 2 To lastRow
grp = NormText(ws.Cells(r, "A").Value) '部門
comp = Key2(ws.Cells(r, "B").Value, ws.Cells(r, "C").Value) 'コード×日付
If Len(grp) = 0 Or InStr(comp, "|") = 0 Then GoTo cont
k = grp & "|" & comp
If seen.Exists(k) Then
delRows.Add r
Else
seen(k) = True
End If
cont:
Next
Dim i As Long
For i = delRows.Count To 1 Step -1
ws.Rows(delRows(i)).Delete
Next
SpeedOff
MsgBox "部門ごとの複数列重複を削除しました: " & delRows.Count & "行"
End Sub
VB- 使いどころ: グループ内で重複排除したい場合の定番。
例題で練習
'例1:コード×日付の重複一覧
Sub Example_List2()
ListDuplicates_TwoColumns
End Sub
'例2:部門×コード×枝番の重複ハイライト
Sub Example_Highlight3()
HighlightDuplicates_ThreeColumns
End Sub
'例3:コード×日付の重複を安全削除(先頭を残す)
Sub Example_Remove2Safe()
RemoveDuplicates_TwoColumns_Safe
End Sub
'例4:標準機能で複数列の重複削除
Sub Example_BuiltInMulti()
RemoveDuplicates_BuiltIn_Multi
End Sub
'例5:部門ごとにコード×日付の重複削除
Sub Example_GroupMulti()
RemoveDuplicates_ByGroup_MultiKey
End Sub
VB実務の落とし穴と対策
- 日付の文字列混在で誤判定
- 対策: 比較前に
NormDateTextでyyyy-mm-ddに統一。
- 対策: 比較前に
- 表記揺れ(空白・大小文字)で別物扱い
- 対策:
NormTextで正規化。必要なら全角→半角も検討。
- 対策:
- 列順や見出し変更で壊れる
- 対策: 見出し検索(Find)で列特定に拡張すると頑健。
- いきなり削除が不安
- 対策: まず一覧化・色ハイライト→承認→“下から削除”の2段階。
- 大量データで遅い
- 対策: Range→配列化+Dictionary(今回のテンプレはセル直読でも十分だが、必要に応じて配列化へ)。
