既存のExcelファイルに2つのCSVデータを取り込む

スポンサーリンク
この記事は約13分で読めます。

完成イメージ:主な流れ

  1. マクロを実行すると、「注文」CSVを選ぶダイアログが出る → 選択
  2. マクロが「注文」CSVを開き、Sheet1のA2セルから下へ連続で貼り付ける
  3. 続いて「品名」CSVを選ぶダイアログが出る → 選択
  4. マクロが「品名」CSVを読み込み、B,C,D列をキー(連結文字列など)として「パターン」列の値をメモリに保持
  5. 先ほど取り込んだ「注文」データの各行(B列,C列,D列)をキーに照合し、一致するものがあれば**E列に「パターン」**を書き込む

「注文」CSVのパスをファイルダイアログで取得し、Sheet1へ貼り付け

Option Explicit

Sub ImportTwoCSVs()

    Dim ws As Worksheet
    Set ws = ThisWorkbook.Worksheets("Sheet1")  ' 取り込み先をSheet1とする

    '======================================================
    ' [1] 「注文」CSVのパスをファイルダイアログで取得し、Sheet1へ貼り付け
    '======================================================
    Dim orderCsvPath As Variant
    orderCsvPath = Application.GetOpenFilename( _
                    FileFilter:="CSVファイル (*.csv), *.csv", _
                    Title:="【注文CSV】を選択してください")
    If orderCsvPath = False Then
        MsgBox "処理をキャンセルしました(注文CSV未選択)。"
        Exit Sub
    End If

    ' 注文CSVをSheet1のA2セルから展開
    Dim lastRowOrder As Long
    lastRowOrder = ImportCsvToSheet(ws, orderCsvPath, 2, 1)
    ' ※戻り値:貼り付けた最終行(row)を返している

    If lastRowOrder < 2 Then
        MsgBox "注文CSVの取り込みができなかったようです。処理を終了します。"
        Exit Sub
    End If

    MsgBox "「注文」CSVをA2から取り込み完了。最終行:" & lastRowOrder, vbInformation

「品名」CSVを読み込み、「パターン」だけを辞書化して保持

※キーは B,C,D列の連結文字列とする

Dim itemCsvPath As Variant
    itemCsvPath = Application.GetOpenFilename( _
                    FileFilter:="CSVファイル (*.csv), *.csv", _
                    Title:="【品名CSV】を選択してください")
    If itemCsvPath = False Then
        MsgBox "処理をキャンセルしました(品名CSV未選択)。"
        Exit Sub
    End If

    ' 品名CSVを1行ずつ読んで、(B列,C列,D列)→パターン の対応をDictionaryに格納
    Dim dictPattern As Object
    Set dictPattern = CreateObject("Scripting.Dictionary")
    dictPattern.CompareMode = vbTextCompare  ' 大文字小文字を区別しない(必要に応じて)

    Dim ff As Integer
    ff = FreeFile
    Open CStr(itemCsvPath) For Input As #ff

    Dim lineTxt As String
    Dim cols() As String

    Do Until EOF(ff)
        Line Input #ff, lineTxt
        cols = Split(lineTxt, ",")  ' カンマ区切りで分割

        ' 必要な列数が足りない行は無視(例:最低でもD列(Index=3)まである前提)
        If UBound(cols) >= 3 Then
            ' B列=cols(1), C列=cols(2), D列=cols(3) をキーとし、パターン列を取得
            ' 例:パターン列が "品名" CSVの5列目(Index=4)にあるなら
            '     cols(4) が "パターン" 値に該当
            ' あるいはヘッダ付きCSVの場合は、最初の行はスキップなど調整してください

            Dim keyStr As String
            keyStr = cols(1) & "_" & cols(2) & "_" & cols(3)  ' B,C,Dを連結

            Dim patternVal As String
            If UBound(cols) >= 4 Then
                patternVal = cols(4)  ' 5列目(Index=4)がパターン
            Else
                patternVal = ""       ' パターン列が無い or 足りない場合は空
            End If

            If Not dictPattern.Exists(keyStr) Then
                dictPattern.Add keyStr, patternVal
            End If
        End If
    Loop
    Close #ff

    MsgBox "「品名」CSVを読み込み、パターン辞書を作成しました。" & vbCrLf & _
           "(登録件数: " & dictPattern.Count & ")", vbInformation

Sheet1 上に取り込んだ「注文」データの各行(B,C,D列)でキーを作りE列に書き込む

※辞書を参照

 Dim r As Long
    Dim lastRow As Long
    lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row  ' A列最終行(注文CSV取込部分)を想定
    
    For r = 2 To lastRow
        Dim bVal As String: bVal = CStr(ws.Cells(r, 2).Value) ' B列
        Dim cVal As String: cVal = CStr(ws.Cells(r, 3).Value) ' C列
        Dim dVal As String: dVal = CStr(ws.Cells(r, 4).Value) ' D列

        Dim keyCheck As String
        keyCheck = bVal & "_" & cVal & "_" & dVal  ' B,C,D連結

        If dictPattern.Exists(keyCheck) Then
            ws.Cells(r, 5).Value = dictPattern(keyCheck)  ' E列にパターンを書き込み
        Else
            ' 見つからない場合は空欄にする or 何もしない等お好みで
            ' ws.Cells(r, 5).Value = ""
        End If
    Next r

    MsgBox "すべての処理が完了しました。", vbInformation

End Sub

【共通関数】: 指定したCSVを1行ずつ読み込み、Sheetへ貼り付ける

ws: 転記先シート
csvPath: CSVのフルパス
startRow, startCol: 貼り付け開始セル(行,列)

戻り値: 貼り付けした最後の行番号(データが無ければ startRow – 1)

Public Function ImportCsvToSheet(ws As Worksheet, _
                                 ByVal csvPath As String, _
                                 ByVal startRow As Long, _
                                 ByVal startCol As Long) As Long
    Dim fNum As Integer
    Dim lineTxt As String
    Dim spl() As String
    Dim r As Long

    fNum = FreeFile
    Open csvPath For Input As #fNum

    r = startRow

    Do Until EOF(fNum)
        Line Input #fNum, lineTxt
        spl = Split(lineTxt, ",")

        Dim i As Long
        For i = LBound(spl) To UBound(spl)
            ws.Cells(r, startCol + i).Value = spl(i)
        Next i

        r = r + 1
    Loop

    Close #fNum

    ' 最後に書き込んだ行 = r - 1
    ImportCsvToSheet = r - 1
End Function

コード解説

  1. ImportTwoCSVs マクロ
    1. GetOpenFilename によりユーザーに「注文」CSVを選んでもらい、そのパス(orderCsvPath)を取得。
    2. ImportCsvToSheet 関数を使って、Sheet1のA2セル(2行目,1列目) から貼り付ける(全面ペースト)。
      • 貼り付け終わった最終行を戻り値で受け取る(lastRowOrder
    3. 続いて「品名」CSVも同様にファイルダイアログで選択 → Pathを取得。
    4. 「品名」CSVを行単位で読み込み、B列=cols(1), C列=cols(2), D列=cols(3) を文字列連結したものをキーに、パターン列=cols(4) を値にして dictPattern(Dictionary)へ格納。
      • CSVがヘッダ付きの場合などは、最初の1行をスキップする処理を入れるなど、適宜修正して下さい。
      • 「品名」CSVの列構成が違う場合は、cols(1), cols(2), cols(3), cols(4) の部分を書き換えてください。
    5. Sheet1に取り込まれた「注文」データの各行(2行目〜最終行)について、B,C,D列の値を連結したキーdictPattern を検索し、一致すればE列へ「パターン」を書き込み。
  2. ImportCsvToSheet 関数
    • CSVを行単位で読み出し(Line Input)、カンマ区切り(Split)したデータをシートへ横に貼り付けるだけの簡易関数。
    • 書き込んだ最後の行番号を返します。

カスタマイズのポイント

  • CSVヘッダ行がある場合
    • 「1行目はヘッダで、実データは2行目から」などの場合は、最初の Line Input を読み飛ばす実装を入れるか、必要に応じてヘッダ行も貼り付けるなど調整してください。
  • 「品名」CSVのB,C,D 列や「パターン」列の位置が違う場合
    • たとえばB,C,Dが0-basedで cols(3), cols(4), cols(5) などになっている場合や、「パターン」が cols(7) にある場合など、dictPattern に格納するときのインデックスを修正してください。
  • 「パターン」を書き込む列を変えたい場合
    • 上記例ではE列(列番号5)に書いています。別の場所にしたければ ws.Cells(r, 5) を変更してください。
  • 見つからない場合の挙動
    • キーが一致しないときに「#N/A」等を入れる、あるいは空白のままにするなど、お好みに合わせて変更可能です。
  • 複数のシートに分けて取り込みたい
    • Worksheets("Sheet2") のように変更して複数回呼び出すことで、任意のシートへ張り付けられます。
  • 同じフォルダから自動で2つのCSVを読む場合
    • Application.GetOpenFilename で1つめのCSVを取得し、そのパスからフォルダを切り出して、2つめはファイル名のみ指定するといった応用も可能です。

以上のように「注文CSVをまずExcelに取り込み → 品名CSVを辞書化してパターン列だけ追加書き込み」という処理を一括で行うことができます。
実際にはCSVの列構成やヘッダの有無などによって読み取りインデックスを微調整する必要がありますが、根本的な考え方は

  1. CSVをシートに貼り付ける
  2. 別のCSVを読み込んでDictionaryなどで持つ
  3. シート上のキー列(B,C,D)で照合し、必要項目(パターン)を貼り付ける

…という流れになります。ぜひご希望に合わせてカスタマイズしてください。

1行目はヘッダ行、2行目以降が実データ」という場合

CSVの「1行目はヘッダ行、2行目以降が実データ」という場合、最初の1行を読み飛ばすロジックを追加すればOKです。たとえば下記のサンプルでは、Line Input #fileNo, textLine を1回だけ実行して何もせずに破棄してしまい、その後のループで実データのみを処理しています。

Sub ImportCsv_SkipHeader()

    Dim csvFilePath As String
    csvFilePath = "C:\temp\sample.csv"   ' CSVファイルのパスを設定してください
    
    Dim fileNo As Integer
    Dim textLine As String
    Dim spl() As String
    
    fileNo = FreeFile
    Open csvFilePath For Input As #fileNo
    
    ' ---- [1行目(ヘッダ)を読み飛ばす] ----
    If Not EOF(fileNo) Then
        Line Input #fileNo, textLine  ' ←この読み込みで1行目を破棄
    End If
    
    ' ---- [2行目以降(実データ)を読み込む] ----
    Do Until EOF(fileNo)
        Line Input #fileNo, textLine
        spl = Split(textLine, ",")
        
        ' 実データに対する処理をここに記述
        ' 例:シートに書き込むなど
        '     For i = LBound(spl) To UBound(spl)
        '         Cells(rowCount, colCount + i).Value = spl(i)
        '     Next i

    Loop
    
    Close #fileNo
End Sub

にほんブログ村 IT技術ブログ IT技術メモへ

コメント

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