完全結合(フル外部結合)
「基準表と相手表の両方にあるキーは統合、片方だけにあるキーも残す」——それが完全結合(フル外部結合)です。左外部結合+右外部結合を合わせたイメージで、両方のキーを“全部”出すのがポイントです。初心者でも壊れないように、関数型・辞書型・見出し名対応のテンプレを用意しました。
考え方と使い分け
- 最短: 左外部+右外部を作って結合(VLOOKUPで両側補完)
- 大量・高速: 配列+辞書でキーの和集合を作り、両側の値を横付け
- 列順が変わる: 見出し名から列番号を動的取得して安全に参照
- 複数キー: ヘルパー列でキー連結(例:部署|年月)
最短テンプレ:VLOOKUPで両側補完(完全結合)
Sub FullJoin_VLookup()
'基準: Sheet("基準") A=コード, B=名称, C=合計
'相手: Sheet("相手") A=コード, B=他合計
'出力: Sheet("完全結合") … 両方のキーを全部出す
Dim wsB As Worksheet: Set wsB = Worksheets("基準")
Dim wsO As Worksheet: Set wsO = Worksheets("相手")
Dim wsOut As Worksheet
On Error Resume Next
Set wsOut = Worksheets("完全結合")
If wsOut Is Nothing Then Set wsOut = Worksheets.Add: wsOut.Name = "完全結合"
On Error GoTo 0
wsOut.Cells.Clear
wsOut.Range("A1:D1").Value = Array("コード", "名称", "合計", "他合計")
'基準表をコピー
Dim rgB As Range: Set rgB = wsB.Range("A1").CurrentRegion
Dim lastB As Long: lastB = rgB.Rows.Count
wsOut.Range("A2").Resize(lastB - 1, rgB.Columns.Count).Value = rgB.Offset(1).Resize(lastB - 1).Value
'相手表の範囲
Dim rgO As Range: Set rgO = wsO.Range("A1").CurrentRegion
Dim lastO As Long: lastO = rgO.Rows.Count
'基準側に相手値をVLOOKUPで付与
With wsOut.Range("D2:D" & lastB)
.FormulaR1C1 = "=IFERROR(VLOOKUP(RC1," & rgO.Address(True, True, xlA1, True) & ",2,FALSE),0)"
.Value = .Value
End With
'相手表にしかないキーを追加(右外部分)
Dim dictB As Object: Set dictB = CreateObject("Scripting.Dictionary")
Dim i As Long
For i = 2 To lastB
dictB(UCase$(Trim$(CStr(wsOut.Cells(i, 1).Value)))) = True
Next
Dim rOut As Long: rOut = lastB + 1
For i = 2 To lastO
Dim k As String: k = UCase$(Trim$(CStr(wsO.Cells(i, 1).Value)))
If Not dictB.Exists(k) Then
wsOut.Cells(rOut, 1).Value = wsO.Cells(i, 1).Value
wsOut.Cells(rOut, 4).Value = wsO.Cells(i, 2).Value
rOut = rOut + 1
End If
Next
wsOut.Columns.AutoFit
End Sub
VB- ポイント
- 左外部+右外部を組み合わせて完全結合。
- 相手にしかないキーは後から追記。
爆速テンプレ:配列+辞書で完全結合(単一キー)
Sub FullJoin_Dictionary()
'基準: A=コード, B=名称, C=合計
'相手: A=コード, B=他合計
'出力: 両方のキーを全部出す完全結合
Dim wsB As Worksheet: Set wsB = Worksheets("基準")
Dim wsO As Worksheet: Set wsO = Worksheets("相手")
Dim wsOut As Worksheet
On Error Resume Next
Set wsOut = Worksheets("完全結合")
If wsOut Is Nothing Then Set wsOut = Worksheets.Add: wsOut.Name = "完全結合"
On Error GoTo 0
wsOut.Cells.Clear
wsOut.Range("A1:D1").Value = Array("コード", "名称", "合計", "他合計")
'基準辞書(コード→(名称,合計))
Dim vb As Variant: vb = wsB.Range("A1").CurrentRegion.Value
Dim base As Object: Set base = CreateObject("Scripting.Dictionary")
Dim i As Long, key As String
For i = 2 To UBound(vb, 1)
key = UCase$(Trim$(CStr(vb(i, 1))))
base(key) = Array(CStr(vb(i, 2)), Val(vb(i, 3)))
Next
'相手辞書(コード→他合計)
Dim vo As Variant: vo = wsO.Range("A1").CurrentRegion.Value
Dim other As Object: Set other = CreateObject("Scripting.Dictionary")
For i = 2 To UBound(vo, 1)
key = UCase$(Trim$(CStr(vo(i, 1))))
other(key) = Val(vo(i, 2))
Next
'キーの和集合
Dim all As Object: Set all = CreateObject("Scripting.Dictionary")
For Each key In base.Keys: all(key) = True: Next
For Each key In other.Keys: all(key) = True: Next
'出力配列
Dim n As Long: n = all.Count
Dim out() As Variant: ReDim out(1 To n + 1, 1 To 4)
out(1, 1) = "コード": out(1, 2) = "名称": out(1, 3) = "合計": out(1, 4) = "他合計"
Dim rOut As Long: rOut = 2
For Each key In all.Keys
out(rOut, 1) = key
out(rOut, 2) = IIf(base.Exists(key), base(key)(0), "")
out(rOut, 3) = IIf(base.Exists(key), base(key)(1), 0)
out(rOut, 4) = IIf(other.Exists(key), other(key), 0)
rOut = rOut + 1
Next
wsOut.Range("A1").Resize(n + 1, 4).Value = out
wsOut.Columns.AutoFit
End Sub
VB- ポイント
- 完全結合=キーの和集合を作って両側の値を横付け。
- セル往復ゼロで高速。欠損は空欄や0で補完。
見出し名で安全に完全結合(列順変更に強い)
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
Sub FullJoin_ByHeaders()
'見出し名で列位置を取得して完全結合
Dim wsB As Worksheet: Set wsB = Worksheets("基準")
Dim wsO As Worksheet: Set wsO = Worksheets("相手")
Dim rgB As Range: Set rgB = wsB.Range("A1").CurrentRegion
Dim rgO As Range: Set rgO = wsO.Range("A1").CurrentRegion
Dim cKeyB As Long: cKeyB = FindHeader(rgB.Rows(1), "コード")
Dim cNameB As Long: cNameB = FindHeader(rgB.Rows(1), "名称")
Dim cSumB As Long: cSumB = FindHeader(rgB.Rows(1), "合計")
Dim cKeyO As Long: cKeyO = FindHeader(rgO.Rows(1), "コード")
Dim cValO As Long: cValO = FindHeader(rgO.Rows(1), "他合計")
If cKeyB * cNameB * cSumB * cKeyO * cValO = 0 Then MsgBox "見出し不足": Exit Sub
'基準辞書(コード→(名称,合計))
Dim vb As Variant: vb = rgB.Value
Dim base As Object: Set base = CreateObject("Scripting.Dictionary")
Dim i As Long, key As String
For i = 2 To UBound(vb, 1)
key = UCase$(Trim$(CStr(vb(i, cKeyB))))
base(key) = Array(CStr(vb(i, cNameB)), Val(vb(i, cSumB)))
Next
'相手辞書(コード→他合計)
Dim vo As Variant: vo = rgO.Value
Dim other As Object: Set other = CreateObject("Scripting.Dictionary")
For i = 2 To UBound(vo, 1)
key = UCase$(Trim$(CStr(vo(i, cKeyO))))
other(key) = Val(vo(i, cValO))
Next
'キーの和集合を作成
Dim all As Object: Set all = CreateObject("Scripting.Dictionary")
For Each key In base.Keys: all(key) = True: Next
For Each key In other.Keys: all(key) = True: Next
'出力シート準備
Dim wsOut As Worksheet
On Error Resume Next
Set wsOut = Worksheets("完全結合")
If wsOut Is Nothing Then Set wsOut = Worksheets.Add: wsOut.Name = "完全結合"
On Error GoTo 0
wsOut.Cells.Clear
wsOut.Range("A1:D1").Value = Array("コード", "名称", "合計", "他合計")
'出力
Dim rOut As Long: rOut = 2
Dim k As Variant
For Each k In all.Keys
wsOut.Cells(rOut, 1).Value = k
wsOut.Cells(rOut, 2).Value = IIf(base.Exists(k), base(k)(0), "")
wsOut.Cells(rOut, 3).Value = IIf(base.Exists(k), base(k)(1), 0)
wsOut.Cells(rOut, 4).Value = IIf(other.Exists(k), other(k), 0)
rOut = rOut + 1
Next
wsOut.Columns.AutoFit
End Sub
VB解説(初心者向け)
- 完全結合の定義:
両方の表にあるキーは統合、片方だけにあるキーも残す。
→「キーの和集合」を作るのがポイント。 - 見出し名で列特定:
列順が変わっても壊れないようにFindHeader関数で列番号を取得。 - 辞書で高速処理:
- 基準表 →
base(キー) = (名称, 合計) - 相手表 →
other(キー) = 他合計 - 和集合 →
all.Keysをループして両側の値を出力。
- 基準表 →
- 補完:
- 基準にないキー → 名称は空欄、合計は0
- 相手にないキー → 他合計は0
例題で練習
'例1:VLOOKUPで完全結合
Sub Example_Full_VLookup()
FullJoin_VLookup
End Sub
'例2:配列+辞書で完全結合(高速)
Sub Example_Full_Dict()
FullJoin_Dictionary
End Sub
'例3:見出し名で列特定して完全結合(列順変更に強い)
Sub Example_Full_ByHeaders()
FullJoin_ByHeaders
End Sub
VB