新規だけ追加
「前月Aに、今月Bの“新規行だけ”を追加入力したい」——重複はスキップして安全に追加するテンプレです。初心者でも壊れないコツは「キーの正規化」「見出し名で列特定」「配列+辞書」「一括転記」。
共通ユーティリティ(速度・安全)
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 EnsureSheet(ByVal name As String, Optional ByVal clear As Boolean = False) 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
Private Function NormKey(ByVal v As Variant) As String
NormKey = UCase$(Trim$(CStr(v)))
End Function
VB- 速度: 画面/イベント/計算を止めてから処理→復帰。
- 正規化:
Trim + UCaseでキーの表記揺れを吸収。 - EnsureSheet: ログ用や出力用シートを安全に用意。
最短テンプレ:AにBの“新規行だけ”末尾追加(キー=コード)
見出しはA・Bとも「コード/名称/単価」想定。重複キーは追加しません。
Sub AppendOnlyNew_Basic()
SpeedOn
Dim wsA As Worksheet: Set wsA = Worksheets("A")
Dim wsB As Worksheet: Set wsB = Worksheets("B")
Dim rgA As Range: Set rgA = wsA.Range("A1").CurrentRegion
Dim rgB As Range: Set rgB = wsB.Range("A1").CurrentRegion
Dim vA As Variant: vA = rgA.Value
Dim vB As Variant: vB = rgB.Value
'Aの既存キー集合
Dim setA As Object: Set setA = CreateObject("Scripting.Dictionary")
Dim i As Long, k As String
For i = 2 To UBound(vA, 1)
k = NormKey(vA(i, 1))
If Len(k) > 0 Then setA(k) = True
Next
'追加件数カウント
Dim added As Long: added = 0
'Bを走査して未存在キーだけA末尾へ追記
Dim nextRow As Long: nextRow = rgA.Row + rgA.Rows.Count 'CurrentRegionの直下
For i = 2 To UBound(vB, 1)
k = NormKey(vB(i, 1))
If Len(k) > 0 And Not setA.Exists(k) Then
wsA.Cells(nextRow, rgA.Column).Resize(1, rgA.Columns.Count).Value = _
Application.Index(vB, i, 0)
nextRow = nextRow + 1
added = added + 1
End If
Next
'見やすさ
wsA.Rows(1).Font.Bold = True
wsA.Columns.AutoFit
SpeedOff
MsgBox "新規追加: " & added & "件"
End Sub
VB- ポイント
- CurrentRegionの直下に追記: 既存表の次行に安全に追加。
- 重複スキップ: 既存キー辞書で判定して追加ミスを防ぐ。
見出し名で列特定(列順変更に強い)版
現場で列増減や順序が変わっても壊れません。見出し不足なら停止します。
Sub AppendOnlyNew_ByHeaders()
SpeedOn
Dim wsA As Worksheet: Set wsA = Worksheets("A")
Dim wsB As Worksheet: Set wsB = Worksheets("B")
Dim rgA As Range: Set rgA = wsA.Range("A1").CurrentRegion
Dim rgB As Range: Set rgB = wsB.Range("A1").CurrentRegion
Dim vA As Variant: vA = rgA.Value
Dim vB As Variant: vB = rgB.Value
'キー見出し名
Dim keyHeader As String: keyHeader = "コード"
'見出し位置
Dim cKeyA As Long: cKeyA = FindHeader(rgA.Rows(1), keyHeader)
Dim cKeyB As Long: cKeyB = FindHeader(rgB.Rows(1), keyHeader)
If cKeyA = 0 Or cKeyB = 0 Then SpeedOff: MsgBox "キー見出し(コード)が見つかりません": Exit Sub
'A既存キー
Dim setA As Object: Set setA = CreateObject("Scripting.Dictionary")
Dim i As Long, k As String
For i = 2 To UBound(vA, 1)
k = NormKey(vA(i, cKeyA))
If Len(k) > 0 Then setA(k) = True
Next
'B→A追記(列はBの見出しに揃えてAの末尾へ)
'ヘッダー整合が必要なら、列マップを作る(A/B共通見出しだけ追記)
Dim map() As Long
Dim headersCount As Long: headersCount = rgB.Columns.Count
ReDim map(1 To headersCount)
Dim c As Long
For c = 1 To headersCount
Dim h As String: h = CStr(vB(1, c))
Dim pos As Long: pos = FindHeader(rgA.Rows(1), h)
map(c) = pos 'A側で同名見出しの列。無ければ0
Next
Dim nextRow As Long: nextRow = rgA.Row + rgA.Rows.Count
Dim added As Long: added = 0
For i = 2 To UBound(vB, 1)
k = NormKey(vB(i, cKeyB))
If Len(k) > 0 And Not setA.Exists(k) Then
'A側に存在する見出しだけ値を入れる(無い見出しはスキップ)
For c = 1 To headersCount
If map(c) > 0 Then
wsA.Cells(nextRow, map(c)).Value = vB(i, c)
End If
Next
nextRow = nextRow + 1
added = added + 1
End If
Next
wsA.Rows(1).Font.Bold = True
wsA.Columns.AutoFit
SpeedOff
MsgBox "新規追加: " & added & "件(共通見出しのみ反映)"
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- ポイント
- 共通見出しのみ反映: 名称が一致する列だけ安全にコピー。
- 見出し不足は即停止: 事故防止。
複合キー(例:コード×年月)で新規だけ追加
年月で行が増える構成に。複合キー文字連結で未存在だけ追加します。
Private Function BuildKey2(ByVal code As Variant, ByVal ymd As Variant) As String
Dim ym As String
If IsDate(ymd) Then ym = Format$(CDate(ymd), "yyyy-mm") Else ym = CStr(ymd)
BuildKey2 = NormKey(code) & "|" & UCase$(Trim$(ym))
End Function
Sub AppendOnlyNew_MultiKey()
SpeedOn
'列想定:A=コード, B=年月, C=名称, D=単価(見出しあり)
Dim wsA As Worksheet: Set wsA = Worksheets("A")
Dim wsB As Worksheet: Set wsB = Worksheets("B")
Dim rgA As Range: Set rgA = wsA.Range("A1").CurrentRegion
Dim rgB As Range: Set rgB = wsB.Range("A1").CurrentRegion
Dim vA As Variant: vA = rgA.Value
Dim vB As Variant: vB = rgB.Value
'既存複合キー集合(A)
Dim setA As Object: Set setA = CreateObject("Scripting.Dictionary")
Dim i As Long
For i = 2 To UBound(vA, 1)
setA(BuildKey2(vA(i, 1), vA(i, 2))) = True
Next
'追加
Dim nextRow As Long: nextRow = rgA.Row + rgA.Rows.Count
Dim added As Long: added = 0
For i = 2 To UBound(vB, 1)
Dim key As String: key = BuildKey2(vB(i, 1), vB(i, 2))
If Not setA.Exists(key) Then
wsA.Cells(nextRow, rgA.Column).Resize(1, rgA.Columns.Count).Value = _
Application.Index(vB, i, 0)
nextRow = nextRow + 1
added = added + 1
End If
Next
wsA.Rows(1).Font.Bold = True
wsA.Columns.AutoFit
SpeedOff
MsgBox "新規(複合キー)追加: " & added & "件"
End Sub
VB- ポイント
- 年月統一:
yyyy-mm固定で表記揺れ防止。 - 安全区切り: 連結は「|」などを使用。
- 年月統一:
追加前に検証レポート(何が新規かを一覧)
追加する前に「新規候補」を確認したいとき。後で承認フローにも使えます。
Sub PreviewNewRows()
SpeedOn
Dim vA As Variant: vA = Worksheets("A").Range("A1").CurrentRegion.Value
Dim vB As Variant: vB = Worksheets("B").Range("A1").CurrentRegion.Value
Dim setA As Object: Set setA = CreateObject("Scripting.Dictionary")
Dim i As Long: For i = 2 To UBound(vA, 1): setA(NormKey(vA(i, 1))) = True: Next
Dim ws As Worksheet: Set ws = EnsureSheet("新規候補", True)
ws.Range("A1").Resize(1, UBound(vB, 2)).Value = Application.Index(vB, 1, 0)
Dim w As Long: w = 2
For i = 2 To UBound(vB, 1)
Dim k As String: k = NormKey(vB(i, 1))
If Len(k) > 0 And Not setA.Exists(k) Then
ws.Range("A" & w).Resize(1, UBound(vB, 2)).Value = Application.Index(vB, i, 0)
w = w + 1
End If
Next
ws.Rows(1).Font.Bold = True
ws.Columns.AutoFit
SpeedOff
MsgBox "新規候補: " & (w - 2) & "件"
End Sub
VB- ポイント
- 承認前確認: 追記前に“差分候補”を一覧化。
実務の落とし穴と対策
- キー表記揺れで重複判定ミス
- 対策:
NormKey(Trim+UCase)。必要なら半角化・不要記号除去も検討。
- 対策:
- 列順や見出しの不一致
- 対策: 見出し名で列特定し、共通見出しのみ反映する設計に。
- 数値・日付の型ズレで後工程が混乱
- 対策: 追加後に列書式を統一(数値は標準/会計、日付は
yyyy-mm)。
- 対策: 追加後に列書式を統一(数値は標準/会計、日付は
- CurrentRegionが余計な空白や合計行を含む
- 対策: 範囲を明示指定(例:
A1:D& 最終行)に変えるか、合計行は別に切り出す。
- 対策: 範囲を明示指定(例:
例題で練習
'例1:単一キーで新規だけ末尾追加
Sub Example_AppendBasic()
AppendOnlyNew_Basic
End Sub
'例2:見出し名で列特定して新規だけ追加(共通見出しのみ)
Sub Example_AppendByHeaders()
AppendOnlyNew_ByHeaders
End Sub
'例3:複合キー(コード×年月)で新規だけ追加
Sub Example_AppendMultiKey()
AppendOnlyNew_MultiKey
End Sub
'例4:追加前に新規候補を一覧化
Sub Example_PreviewNew()
PreviewNewRows
End Sub
VB