例文を使って繰り返し業務を時短

【マクロ・VBA】アクティブシートと右隣のシート間でマッチしたデータの行を新規シートに貼付け

エクセル、マクロ、VBAのディクショナリで検索シートのデータとアクティブシートの重複チェックして新規シートに貼付け VBA

検索シートのデータとアクティブシートの重複チェック、新規シートに結果を貼り付け

このVBAコードは、アクティブ(Activesheet)なシートと別のシート(前のシート:ActiveSheet.Previous)にあるデータを比較し、重複しているデータを新しいシートに転記するものです。

*Activesheetを選択した状態で実施

Sub 検索シートのデータとアクティブシートの重複チェック、新規シートに結果を貼り付け()

    Dim c As Range
    Dim v() As Variant
    Dim cols As Long
    Dim j As Long
    Dim dic As Object
    Dim newWs As Worksheet
    Dim i As Long
    
    Set dic = CreateObject("Scripting.Dictionary")

    ' 検索シートの値を辞書に格納
    With ActiveSheet.Previous
        For Each c In .Range("A2", .Range("A" & .Rows.Count).End(xlUp))
            If Not dic.Exists(c.Value) Then
                dic.Add c.Value, dic.Count + 1
            End If
        Next
    End With

    With ActiveSheet
        cols = .UsedRange.Cells(.UsedRange.Cells.Count).Column
        
        ReDim v(1 To dic.Count, 1 To cols)
        
        For Each c In .Range("A2", .Range("A" & .Rows.Count).End(xlUp))

            If dic.Exists(c.Value) Then
                i = dic(c.Value)
                For j = 1 To cols
                    v(i, j) = c.EntireRow.Cells(j).Value
                Next
                dic.Remove c.Value ' 重複する値を削除
            End If
        Next
    End With
    
    ' 新規ワークシートを作成して結果を転記
    Set newWs = Worksheets.Add(After:=ActiveSheet.Next)
    newWs.Name = ActiveSheet.Name & "_作成" & VBA.Format(Now(), "h時mm分ss秒")
    newWs.Columns("A").Resize(, cols).ClearContents
    newWs.Range("A2").Resize(dic.Count, cols).Value = v
    newWs.Select

    ' 辞書の解放
    Set dic = Nothing

    MsgBox "転記完了"

End Sub

まず、スクリプト内で「Scripting.Dictionary」オブジェクトを作成します。これは、データを格納するための連想配列のようなものです。そして、前のシートから全体をループし、各行のA列の値をディクショナリに格納します。これにより、前のシートにある重複しない値が抽出されます。

次に、アクティブなシートをループして、各行のA列の値が前のシートのディクショナリに存在するかどうかを確認します。もしそうであれば、その行の値を配列にコピーします。このようにして、前のシートとアクティブなシートのデータが重複している場合に、アクティブなシートのデータを新しい配列に格納することができます。

最後に、新しいシートを作成し、重複しないデータのみを含む配列を新しいシートに転記します。そして、転記が完了したことを示すメッセージが表示されます。

<ポイント>

  • 辞書の追加処理に重複チェックを追加し、重複する値を格納しないようにしています。
  • 辞書から値を取り出すときに、Keys メソッドを使わずに Item メソッドを使うようにしました。
  • 新規ワークシートを作成する前にエラー処理を解除し、エラーが発生した場合はそのまま処理を続けます。
  • 新規ワークシートを変数に格納しておき、直接参照するようにしました。
  • 結果の転記に際して、配列のサイズを調整してから値を格納するようにしました。
  • 辞書を解放する処理を追加しました。
  • dic(c.Value) = dic.Count + 1:その値をキー、1からの連番をデータとして辞書登録
  • ReDim v(1 To dic.Count, 1 To cols) :空白行はスケルトンにする
  • もし辞書にあれば(シート2にあれば)1行分のイメージを配列に格納
  • .Columns(“A”).Resize(, cols).ClearContents:最初に転記領域のクリア

シート指定/新規シート記入/マッチング/行/新規シート貼付け

このVBAコードは、指定したシートとアクティブシートの列Aの値を比較して、重複している行を新規シートにコピーするものです。

Sub 検索シートのデータとアクティブシート間、マッチングしているものを新規シートに貼り付け()
    
Dim c As Range
Dim v() As Variant
Dim cols As Long
Dim j As Long
Dim dic As Object

Set dic = CreateObject("Scripting.Dictionary")

With Sheets("検索データ")
    
    For Each c In .Range("A2", .Range("A" & .Rows.Count).End(xlUp))
            dic(c.Value) = dic.Count + 1
    Next

End With


With ActiveSheet
    
    cols = .UsedRange.Cells(.UsedRange.Cells.Count).Column
        
    ReDim v(1 To dic.Count, 1 To cols)
        
    For Each c In .Range("A2", .Range("A" & .Rows.Count).End(xlUp))
            
        If dic.Exists(c.Value) Then
            
            For j = 1 To cols
                    v(dic(c.Value), j) = c.EntireRow.Cells(j).Value
            Next
        
        End If
    Next
    
End With
    
Worksheets.Add(After:=ActiveSheet.Next).Name = ActiveSheet.Name & "_作成" & VBA.Format(Now(), "h時mm分ss秒")

With ActiveSheet
        .Columns("A").Resize(, cols).ClearContents
        .Range("A2").Resize(UBound(v, 1), UBound(v, 2)).Value = v
        .Select
End With

MsgBox "転記完了"
End Sub

まず、Scripting.Dictionaryオブジェクトを作成し、指定したシート(“検索データ”)の列Aの値をキーとして、行数を値として格納します。これにより、指定したシートの列Aに重複する値がなくなり、一意のキーとなります。

次に、アクティブシートの列Aの値を比較して、Dictionaryオブジェクトに存在する場合は、その行の値を配列に格納します。これにより、指定したシートとアクティブシートの重複した行のみが、新規シートにコピーされます。

最後に、新規シートを作成し、配列の値を新規シートに貼り付けます。また、新規シートには、アクティブシートの名前と現在の日時を含む名前が付けられます。最後に、転記が完了した旨のメッセージが表示されます。

v(dic(c.Value), j) = c.EntireRow.Cells(j).Value:

・もし辞書にあれば(シート2にあれば)1行分のイメージを配列に格納

・.Columns(“A”).Resize(, cols).ClearContents:最初に転記領域のクリア

マッチング/行/ディクショナリ パターン2

このVBAコードは、2つのExcelシートを比較して、マッチングしているデータを新規シートに貼り付けるマクロです。以下、各行ごとに解説します。

Sub シート突合_行_ディクショナリ_新規シート貼り付け()

Dim wb1 As Workbook
Set wb1 = ThisWorkbook
Dim ws1 As Worksheet
Set ws1 = wb1.ActiveSheet

Dim LastCol1 As Long
LastCol1 = ws1.Cells(1, Columns.Count).End(xlToLeft).Column

Dim wb2 As Workbook
Set wb2 = ThisWorkbook
Dim ws2 As Worksheet
Set ws2 = wb2.ActiveSheet.Next
Dim LastRow2 As Long
LastRow2 = ws2.Cells(Rows.Count, 1).End(xlUp).Row
Dim LastCol2 As Long
LastCol2 = ws2.Cells(1, Columns.Count).End(xlToLeft).Column

ws1.Activate

'ファイル突合
Dim myDic As Object
Dim i As Long
Dim LastColumn1 As Long
LastColumn1 = ws1.Cells(2, Columns.Count).End(xlToLeft).Column + 1

Set myDic = CreateObject("Scripting.Dictionary")

'相手ファイル
With ws2
    For i = 2 To LastRow2 + 1
        DoEvents
        On Error Resume Next
        If Not myDic.Exists(ws2.Cells(i, 1).Value) Then
            myDic.Add ws2.Cells(i, 1).Value, ws2.Cells(i, 1).Value
        End If
        Application.StatusBar = i - 2 & "/" & LastRow2 & " 完了"
    Next i
    On Error GoTo 0
End With

'このファイル
Dim LastRow1 As Long
LastRow1 = ThisWorkbook.ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row

With ws1
    For i = 2 To LastRow1 + 1
        DoEvents
        On Error Resume Next
        If myDic.Exists(ws1.Cells(i, 1).Value) Then
            ws1.Cells(i, LastColumn1).Value = myDic.Item(ws1.Cells(i, 1).Value)
        End If
        Application.StatusBar = i - 2 & "/" & LastRow1 & " 完了"
    Next i
    On Error GoTo 0
End With

myDic.RemoveAll
Set myDic = Nothing
Set wb2 = Nothing
Set ws2 = Nothing

MsgBox "完了"
End Sub

1行目:Sub宣言。マクロの名前を指定します。

3-6行目:変数wb1とws1を作成し、アクティブなワークブックとアクティブなシートをそれぞれに割り当てます。

9-10行目:変数LastCol1を作成し、ws1の1行目の最後の列を取得しています。

18-20行目:変数wb2とws2を作成し、アクティブなワークブックの次のシートをそれぞれに割り当て、そのシートの最後の行と最後の列を取得しています。

25-26行目:変数myDicを作成し、Scripting.Dictionaryオブジェクトを作成しています。

29-30行目:変数LastColumn1を作成し、ws1の2行目の最後の列に1を加えたものを取得しています。

32-40行目:変数myDicを使用して、2番目のシートのデータをループし、キーとして列Aの値を使用してmyDicにデータを追加しています。

42-49行目:アクティブなワークブックのデータをループし、列Aの値を使用してmyDicからデータを取得し、2番目のシートに対応する行にコピーしてい

54-55行目:myDicをクリアします。

56-59行目:MsgBoxで処理完了のメッセージを表示します。

シート指定/新規シート記入/マッチング/行/新規シート貼付け

このVBAマクロは、アクティブなシートと「検索データ」という名前の別のシートの間で、特定のカラムに一致するデータを検索し、その一致するデータを新しいシートに貼り付けるものです。

Sub 検索シートのデータとアクティブシート間、マッチングしているものを新規シートに貼り付け()
    
Dim c As Range
Dim v() As Variant
Dim cols As Long
Dim j As Long
Dim dic As Object

Set dic = CreateObject("Scripting.Dictionary")

    
With Sheets("検索データ")
    
    For Each c In .Range("A2", .Range("A" & .Rows.Count).End(xlUp))
            dic(c.Value) = dic.Count + 1
    Next

End With


With ActiveSheet
    
    cols = .UsedRange.Cells(.UsedRange.Cells.Count).Column    'シート1の列数取得 ’Dim LastCol1 As Long   ’LastCol1 = ws1.Cells(1, Columns.Count).End(xlToLeft).Column
        
    ReDim v(1 To dic.Count, 1 To cols) '空白行スケルトン
        
    
    For Each c In .Range("A2", .Range("A" & .Rows.Count).End(xlUp))
            
        
        If dic.Exists(c.Value) Then                          'もし辞書にあれば(シート2にあれば)1行分のイメージを配列に格納
            
            For j = 1 To cols
                    v(dic(c.Value), j) = c.EntireRow.Cells(j).Value
            Next
        
        End If
    Next
    
End With
    
'-----------------------------------
Worksheets.Add(After:=ActiveSheet.Next).Name = ActiveSheet.Name & "_作成" & VBA.Format(Now(), "h時mm分ss秒")


With ActiveSheet      'Sheets("Sheet2")
        '最初に転記領域のクリア
        .Columns("A").Resize(, cols).ClearContents
        .Range("A2").Resize(UBound(v, 1), UBound(v, 2)).Value = v
        .Select
End With

MsgBox "転記完了"
End Sub

まず、’CreateObject(“Scripting.Dictionary”)を使用して、データを保存するための辞書オブジェクトを作成します。この辞書オブジェクトは、検索データシートからカラムAの値を読み取り、一致するデータを検索するために使用されます。

次に、アクティブなシートから、一致するデータを検索するために、同じくカラムAの値を読み取ります。そして、’dicという辞書オブジェクトを使用して、アクティブなシートの値が検索データシートに存在するかどうかを調べます。もし辞書にあれば、その行の各列のデータを配列に格納します。最後に、配列に格納された一致するデータを新しいシートに貼り付けます。

具体的には、新しいシートを作成し、一致するデータを貼り付ける前に、新しいシートの列をクリアして、貼り付けのための領域を用意します。そして、配列からデータを取り出して、新しいシートに貼り付けます。

最後に、’MsgBoxを使用して、転記が完了したことを示すメッセージを表示します。

ディクショナリ

このVBAコードは、検索シートのデータとアクティブシートのデータをマッチングして、マッチしたものを新しいシートに転記するコードです。

Sub ディクショナリ_未検証66() 
    Dim c As Range
    Dim v() As Variant
    Dim cols As Long
    Dim j As Long
    Dim dic As Object
    Dim k As Long
    Dim baseV() As Variant

    Set dic = CreateObject("Scripting.Dictionary")

    With Sheets("検索データ")
        'シート1の列数取得
        cols = .UsedRange.Cells(.UsedRange.Cells.Count).Column
        'シート1のD1からD列のデータ最終行までのセルを1つずつ取り出す
        For Each c In .Range("A2", .Range("A" & .Rows.Count).End(xlUp))
            'その1行のイメージを辞書に登録
            dic(c.Value) = c.EntireRow.Resize(, cols).Value
        Next
    End With

    ReDim baseV(1 To 1, 1 To cols) '空白行スケルトン

    With ActiveSheet
        'シート2のA1からA列のデータ最終行までのセルを1つずつ取り出す
        With .Range("A1", .Range("A" & .Rows.Count).End(xlUp))
            ReDim v(1 To .Rows.Count)
            For Each c In .Cells
                k = k + 1
                If dic.Exists(c.Value) Then 'シート1にあれば
                    v(k) = dic(c.Value)
                Else
                    v(k) = baseV
                End If
            Next
        End With
    End With
        Worksheets.Add(After:=ActiveSheet.Next).Name = ActiveSheet.Name & "_作成" & VBA.Format(Now(), "h時mm分ss秒")
    'Worksheets.Add
    'ActiveSheet.Name = "output"

    'Do
        'If Err.Number = 0 Then Exit Do
        'Err.Clear
        'Num = Num + 1
        'ActiveSheet.Name = "output" & "_" & Num
    'Loop
    
    'Dim outputSheet As Worksheet
    'Set outputSheet = ActiveSheet

    With ActiveSheet
        .Range("A2").Select
        '最初に転記領域のクリア
        '.Columns("A").Resize(, cols).ClearContents
        .Range("A2").Resize(UBound(v, 1), UBound(v, 2)).Value = v
        'Sheets("検索データ").Range("A2").Resize(UBound(v, 1), UBound(v, 2)).Value = v
        .Select
    End With
        
    MsgBox "転記終了"
 End Sub

まず、辞書オブジェクトを作成し、検索データシートから各行のA列の値をキーとして、その行全体のデータを辞書の値に登録します。次に、アクティブシートのA列の値をキーとして、辞書に登録されている値を取得し、v配列に格納します。辞書にキーが存在しない場合は、空白行スケルトン(baseV配列)を使用します。最後に、v配列を新しいシートに貼り付けます。

ディクショナリ2

Sub 作成2() 
    Const KENSAKU_CLM As Long = 2 '「転記先」シートB列
    Const KENSAKU_ROW As Long = 4 '「転記先」シート4行目

    Const MOTO_KEY_CLM As Long = 3 '「元表」シートのキー列(社名列:C列)
    Const MOTO_KEY_ROW As Long = 7 '「元表」シートのキー行(項目見出し行:7行目)

    Dim Sh_Moto As Worksheet    '「元表」シート
    Dim Sh_Tenki As Worksheet   '「転記先」シート

    'Dictionaryオブジェクトの宣言
    Dim dicShamei As Object     '元表の社名行番号ディクショナリ
    Dim dicKomoku As Object     '元表の項目名列番号ディクショナリ

    Dim iRRow As Integer        '元表シートの読込行
    Dim iRCol As Integer        '元表シートの読込列

    Dim iWRow As Integer        '転記先シートの出力行
    Dim iWCol As Integer        '転記先シートの出力列

    Set Sh_Moto = Worksheets("元表")
    Set Sh_Tenki = Worksheets("転記先")

    Set dicShamei = CreateObject("Scripting.Dictionary")
    Set dicKomoku = CreateObject("Scripting.Dictionary")

    '【ディクショナリ作成】
    '元表シートから社名のディクショナリを作成
    For iRRow = 8 To Sh_Moto.Cells(8, MOTO_KEY_CLM).End(xlDown).Row
        '社名をキーとして行番号をディクショナリに保管(同じ社名が複数存在した場合、後勝ちで行番号が上書きされます)
        dicShamei(Sh_Moto.Cells(iRRow, "C").Value) = iRRow
    Next
    '元表シートから項目名のディクショナリを作成
    For iRCol = 4 To Sh_Moto.Cells(MOTO_KEY_ROW, 4).End(xlToRight).Column
        '項目名をキーとして列番号をディクショナリに保管
        dicKomoku(Sh_Moto.Cells(7, iRCol).Value) = iRCol
    Next

    '【転記処理】
    '転記先シートの社名ループ
    For iWRow = 5 To Sh_Tenki.Cells(5, KENSAKU_CLM).End(xlDown).Row
        '社名から元表の行番号を取得
        If dicShamei.Item(Sh_Tenki.Cells(iWRow, KENSAKU_CLM).Value) = "" Then
            '社名から行番号が取得できない場合は何もしない
        Else
            '元表の行番号を取得
            iRRow = dicShamei.Item(Sh_Tenki.Cells(iWRow, KENSAKU_CLM).Value)

            '転記先シートの項目ループ
            For iWCol = 4 To Sh_Moto.Cells(KENSAKU_ROW, 4).End(xlToRight).Column
                '項目名から元表の列番号を取得
                If dicKomoku.Item(Sh_Tenki.Cells(KENSAKU_ROW, iWCol).Value) = "" Then
                    '項目名から列番号が取得できない場合は何もしない
                Else
                    '元表の列番号を取得
                    iRCol = dicKomoku.Item(Sh_Tenki.Cells(KENSAKU_ROW, iWCol).Value)
                    '「元表」シートの取得行・取得列のセルの値を、「転記先」シートの出力行・出力列に出力する
                    Sh_Tenki.Cells(iWRow, iWCol).Value = Sh_Moto.Cells(iRRow, iRCol).Value
                End If
            Next iWCol
        End If
    Next iWRow
MsgBox "完了"
End Sub

コメント

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