Excel VBA 逆引き集 | 実務テンプレ完全版(超再利用部品) – VLOOKUP高速テンプレ

Excel VBA
スポンサーリンク
  1. ねらい:VLOOKUPの“遅い・不安定”を捨て、配列I/O+Dictionaryで爆速・堅牢にする
    1. 重要ポイントの深掘り
  2. 基本部品:辞書生成・正規化・安全な比較モード
    1. NewDict(参照設定不要)とキー整形
    2. Range⇔配列の一括I/O
  3. 単一キー:VLOOKUP高速テンプレ(片側辞書→即参照)
    1. 片側辞書化+結果一括書き戻し(貼って動く)
    2. 重要ポイントの深掘り
  4. 複合キー:2列以上で一意化するテンプレ
    1. 安全な区切り文字でキーを束ねる(Chr(30)推奨)
    2. 重要ポイントの深掘り
  5. 多段参照:コード→ID→属性の二段VLOOKUPを線形時間で
    1. 段積み辞書で遅い式連鎖を廃止
    2. 重要ポイントの深掘り
  6. 逆引き:値→複数のキー(多対一・一対多)を返す
    1. 値からキー一覧を返すテンプレ(重複保持)
    2. 重要ポイントの深掘り
  7. 欠損・型混在の扱い:安全なデフォルトと数値変換
    1. 欠損時のポリシーと数値変換補助
    2. 重要ポイントの深掘り
  8. 例題の通し方:顧客コードから顧客名を高速付与、未登録は空に
    1. 手順(単一キー)
    2. 期待動作の確認ポイント
  9. 運用の深掘り:拡張・安全装置・見える化
    1. 拡張と保守
    2. 安全装置
    3. 見える化
  10. 落とし穴と対策(深掘り)
    1. 正規化の不足で誤ミスヒット
    2. 逐次セル書きで遅い
    3. 複合キーの衝突
    4. 多段参照で中間値を未正規化
  11. まとめ:配列I/O+辞書化+正規化で、VLOOKUPを“速く・壊れない”部品にする

ねらい:VLOOKUPの“遅い・不安定”を捨て、配列I/O+Dictionaryで爆速・堅牢にする

VLOOKUPは大量行や複合キーで遅く、式管理が崩れがちです。実務では「片側を辞書化→一括照合→配列で結果へ」の型にすると、数万〜数十万行でも高速・安定に動きます。初心者でも貼って動く“超再利用部品”を、単一キー・複合キー・多段参照・逆引き・欠損処理までまとめて用意します。

重要ポイントの深掘り

  • 核設計: シート→配列(一次読み込み)→辞書(キー→値)→結果配列→一括書き戻し。セルを行き来しないことが速度の源泉です。
  • キー正規化: Trim+LCase(必要なら全半角統一)。入口で揺らぎを潰して、誤マッチと再計算コストを防ぎます。
  • 存在分岐の最小化: d(key)=value で追加・更新を統一。Exists は「ヒット時のみ特別処理」に限定すると速く・読みやすくなります。

基本部品:辞書生成・正規化・安全な比較モード

NewDict(参照設定不要)とキー整形

' ModVL_Base.bas
Option Explicit

Public Function NewDict(Optional ByVal textCompare As Boolean = True) As Object
    Dim d As Object: Set d = CreateObject("Scripting.Dictionary")
    d.CompareMode = IIf(textCompare, 1, 0) ' 1=Text(大小無視), 0=Binary
    Set NewDict = d
End Function

Public Function NormKey(ByVal v As Variant) As String
    NormKey = LCase$(Trim$(CStr(v)))
End Function
VB

Range⇔配列の一括I/O

Public Function ReadRegion(ByVal ws As Worksheet, Optional ByVal topLeft As String = "A1") As Variant
    ReadRegion = ws.Range(topLeft).CurrentRegion.Value
End Function

Public Sub WriteRegion(ByVal ws As Worksheet, ByVal a As Variant, Optional ByVal topLeft As String = "A1")
    ws.Range(topLeft).Resize(UBound(a, 1), UBound(a, 2)).Value = a
End Sub
VB

単一キー:VLOOKUP高速テンプレ(片側辞書→即参照)

片側辞書化+結果一括書き戻し(貼って動く)

' ModVL_Single.bas
Option Explicit

' srcSheet: 照合元(キーがA列)、masterSheet: マスタ(キーA列、取りたい値はB列)
Public Sub FastVlookup(ByVal srcSheet As String, ByVal masterSheet As String, _
                       Optional ByVal outColLetter As String = "Z")
    Dim wsS As Worksheet: Set wsS = Worksheets(srcSheet)
    Dim wsM As Worksheet: Set wsM = Worksheets(masterSheet)

    Dim aS As Variant: aS = ReadRegion(wsS) ' 元データ
    Dim aM As Variant: aM = ReadRegion(wsM) ' マスタ

    Dim d As Object: Set d = NewDict(True)
    Dim r As Long
    For r = 2 To UBound(aM, 1)
        d(NormKey(aM(r, 1))) = aM(r, 2) ' キーA→値B
    Next

    Dim out() As Variant: ReDim out(1 To UBound(aS, 1), 1 To 1)
    out(1, 1) = "Lookup" ' ヘッダー
    For r = 2 To UBound(aS, 1)
        Dim k As String: k = NormKey(aS(r, 1))
        out(r, 1) = IIf(d.Exists(k), d(k), "") ' 欠損は空文字(仕様に合わせて変更)
    Next

    wsS.Range(outColLetter & "1").Resize(UBound(out, 1), 1).Value = out ' 一括書き戻し
End Sub
VB

重要ポイントの深掘り

  • ヘッダー固定: 1行目は見出し扱い。データは2行目から走査すると安全です。
  • 欠損の扱い: 空文字・0・“N/A”など、運用と下流仕様に合わせて統一し、後続集計が崩れないようにします。

複合キー:2列以上で一意化するテンプレ

安全な区切り文字でキーを束ねる(Chr(30)推奨)

' ModVL_Composite.bas
Option Explicit
Private Const SEP As String = Chr$(30)

Private Function MakeKey2(ByVal v1 As Variant, ByVal v2 As Variant) As String
    MakeKey2 = NormKey(v1) & SEP & NormKey(v2)
End Function

Public Sub FastVlookup2Keys(ByVal srcSheet As String, ByVal masterSheet As String, _
                            Optional ByVal outColLetter As String = "Z")
    Dim wsS As Worksheet: Set wsS = Worksheets(srcSheet)
    Dim wsM As Worksheet: Set wsM = Worksheets(masterSheet)
    Dim aS As Variant: aS = ReadRegion(wsS)
    Dim aM As Variant: aM = ReadRegion(wsM)

    Dim d As Object: Set d = NewDict(True)
    Dim r As Long
    For r = 2 To UBound(aM, 1)
        d(MakeKey2(aM(r, 1), aM(r, 2))) = aM(r, 3) ' キーA,B → 値C
    Next

    Dim out() As Variant: ReDim out(1 To UBound(aS, 1), 1 To 1)
    out(1, 1) = "Lookup"
    For r = 2 To UBound(aS, 1)
        Dim k As String: k = MakeKey2(aS(r, 1), aS(r, 2))
        out(r, 1) = IIf(d.Exists(k), d(k), "")
    Next

    wsS.Range(outColLetter & "1").Resize(UBound(out, 1), 1).Value = out
End Sub
VB

重要ポイントの深掘り

  • 衝突回避: 区切りに“ありえない文字”を使うと、値の連結による誤結合を防げます。
  • 正規化の一貫: 片側だけ正規化しても意味がありません。辞書登録時も参照時も同じ正規化関数を通します。

多段参照:コード→ID→属性の二段VLOOKUPを線形時間で

段積み辞書で遅い式連鎖を廃止

' ModVL_MultiStage.bas
Option Explicit

Public Sub FastVlookup2Stage(ByVal srcSheet As String, ByVal master1Sheet As String, ByVal master2Sheet As String, _
                             Optional ByVal outColLetter As String = "Z")
    ' 段1:コードA→ID、段2:ID→属性
    Dim aS As Variant: aS = ReadRegion(Worksheets(srcSheet))
    Dim aM1 As Variant: aM1 = ReadRegion(Worksheets(master1Sheet))
    Dim aM2 As Variant: aM2 = ReadRegion(Worksheets(master2Sheet))

    Dim d1 As Object: Set d1 = NewDict(True)
    Dim d2 As Object: Set d2 = NewDict(True)

    Dim r As Long
    For r = 2 To UBound(aM1, 1): d1(NormKey(aM1(r, 1))) = aM1(r, 2): Next ' Code→ID
    For r = 2 To UBound(aM2, 1): d2(NormKey(aM2(r, 1))) = aM2(r, 2): Next ' ID→Attr

    Dim out() As Variant: ReDim out(1 To UBound(aS, 1), 1 To 1)
    out(1, 1) = "Attr"
    For r = 2 To UBound(aS, 1)
        Dim code As String: code = NormKey(aS(r, 1))
        If d1.Exists(code) Then
            Dim id As String: id = NormKey(d1(code))
            out(r, 1) = IIf(d2.Exists(id), d2(id), "")
        Else
            out(r, 1) = ""
        End If
    Next
    Worksheets(srcSheet).Range(outColLetter & "1").Resize(UBound(out, 1), 1).Value = out
End Sub
VB

重要ポイントの深掘り

  • 式連鎖の置換: VLOOKUPの入れ子は列追加で壊れます。辞書段積みなら列変更に強く、計算量も線形に抑えられます。
  • 中間結果の正規化: 段1の出力(ID)も必ず NormKey を通してから段2に渡します。

逆引き:値→複数のキー(多対一・一対多)を返す

値からキー一覧を返すテンプレ(重複保持)

' ModVL_Reverse.bas
Option Explicit

Public Function BuildReverseIndex(ByVal wsName As String) As Object
    Dim a As Variant: a = ReadRegion(Worksheets(wsName))
    Dim idx As Object: Set idx = NewDict(True)
    Dim r As Long
    For r = 2 To UBound(a, 1)
        Dim k As String: k = NormKey(a(r, 1)) ' キー
        Dim v As String: v = NormKey(a(r, 2)) ' 値
        If Not idx.Exists(v) Then
            Dim col As Collection: Set col = New Collection
            col.Add k: Set idx(v) = col
        Else
            idx(v).Add k
        End If
    Next
    Set BuildReverseIndex = idx
End Function
VB

重要ポイントの深掘り

  • 多対一の現実: 実務では「同じ値に複数キー」が普通。Collection でキー群を保持すると“逆引き”や重複監査が簡単になります。
  • 返却型の取り扱い: Items をさらに配列化してシートへ出すなど、出口を決めておくと使い回しやすいです。

欠損・型混在の扱い:安全なデフォルトと数値変換

欠損時のポリシーと数値変換補助

' ModVL_Safety.bas
Option Explicit

Public Function DefaultIfMissing(ByVal exists As Boolean, ByVal found As Variant, Optional ByVal defVal As Variant = "") As Variant
    DefaultIfMissing = IIf(exists, found, defVal)
End Function

Public Function ToNumberOrZero(ByVal v As Variant) As Double
    If IsNumeric(v) Then ToNumberOrZero = CDbl(v) Else ToNumberOrZero = 0#
End Function
VB

重要ポイントの深掘り

  • 欠損は仕様化: 「空文字」「0」「N/A」など、下流のピボットや集計が壊れない値に統一します。
  • 数値は数値で: 文字数値のまま比較すると順序や集計が崩れます。CDbl/Valで明示変換してから使います。

例題の通し方:顧客コードから顧客名を高速付与、未登録は空に

手順(単一キー)

' ModVL_Example.bas
Option Explicit

Public Sub Demo_FastVlookup()
    ' Input: Data(A:顧客コード)、Master(A:顧客コード, B:顧客名)
    FastVlookup "Data", "Master", "Z" ' DataのZ列へ顧客名を高速付与
    MsgBox "顧客名付与が完了しました。", vbInformation
End Sub
VB

期待動作の確認ポイント

  • 正しく付与: 登録済みコードに顧客名が入り、未登録は空。
  • 速度体感: 数万行でも「一瞬」。セル関数より桁違いに速いはずです。

運用の深掘り:拡張・安全装置・見える化

拡張と保守

  • 列の変更耐性: マスタ列が増減しても、辞書化の列指定を変えるだけで安全に追随できます。
  • 設定外出し: シート名・出力列・キー列の定義は config.ini に外出しすると、非エンジニアでも変更可能になります。

安全装置

  • 重複検知: マスタ側でキー重複があれば警告ログを残す。辞書化前に d.Exists(key) を見て“二重登録”の一覧を作ると、品質が上がります。
  • ログ: 何件ヒット/何件欠損を Log に記録して、品質メトリクスを管理する。

見える化

  • 色分け: 結果列で欠損(空)を薄赤、ヒットを薄緑に条件付き書式。レビュー時の確認が楽になります。

落とし穴と対策(深掘り)

正規化の不足で誤ミスヒット

半角/全角・大小・余分スペースが揺らぎの原因。入口で NormKey を必ず通す。

逐次セル書きで遅い

結果は配列へ作って最後に一括書き戻し。セル毎書きは避ける。

複合キーの衝突

“安全な区切り”を使う。SEPを Chr(30) などに固定して誤連結を根絶。

多段参照で中間値を未正規化

段1出力(ID)も必ず正規化して段2へ。ここを怠るとヒット漏れが起きます。


まとめ:配列I/O+辞書化+正規化で、VLOOKUPを“速く・壊れない”部品にする

  • 片側辞書→一括照合→結果配列→一括書き戻しが定番の型。
  • 正規化・欠損ポリシー・区切り文字を先に決めて、運用品質を守る。
  • 複合キーと多段辞書で複雑な参照も線形時間。逆引きで監査も容易。

タイトルとURLをコピーしました