VBA100本ノック 40本目:複数ブックの統合

この記事から得るもの

他のBookへのCopy、Pasteする方法。
FSOを使用して、ファイルを開く。
Range.CurrentRegionの見出しを除いたデータをCopy、Pasteする方法。

1 今回のお題

「data」フォルダ内のExcelファイルについて、シート「2020年12月」のA1からの連続表範囲を集めます。※このシートが無いファイルもある。
自身の既存シート「2020年12月」に集めてください。
1行目は見出しなので2件目からは除く。
※ブック指定と「data」のパス位置は任意

f:id:bimori466:20201227064550p:plain

excel-ubara.com

2 今回のお題の意図

1 該当するSheetが存在するかの確認。
2 最初のコピー時には見出しもコピーする。

3 回答

私の最初の回答

Sub ノック40本目_1()

'FSOを宣言
Dim fso_lord As Object: Set fso_lord = CreateObject("scripting.filesystemobject")

'pathの設定
wbPath = ThisWorkbook.Path & "\40本目\"

'ファイルをmyfilesにSetする。
Dim myfiles As Object: Set myfiles = fso_lord.getfolder(wbPath).Files

'主処理
Dim bookCount As Integer: bookCount = 0: Dim file As Object

For Each file In myfiles
    If Not file.Name Like "~$*" Or file.Name Like ".xlsx" Then
        'ファイルを開く
        Workbooks.Open wbPath & file.Name
        
        'Sheetに”2020年12月”があるか調べる。
        For Each sh In Sheets
            shCount = shCount + 1
            shCounts = Sheets.Count
            
            'Bookが1回目の書込み処理
            If sh.Name = "2020年12月" And bookCount = 0 Then
                Worksheets(sh.Name).Select
                ActiveSheet.Range("A1").CurrentRegion.Copy
                
                'ファイルを閉じる
                Application.DisplayAlerts = False
                ActiveWorkbook.Close
                Application.DisplayAlerts = True
                
                ActiveSheet.Paste Destination:=Range("A1")
                
                bookCount = bookCount + 1
                Exit For
            
            'Bookが2回目以降の書込み処理
            ElseIf sh.Name = "2020年12月" And bookCount > 0 Then
                Worksheets(sh.Name).Select
                ActiveSheet.Range("A1").CurrentRegion.Offset(1, 0).Copy
                
                'ファイルを閉じる
                Application.DisplayAlerts = False
                ActiveWorkbook.Close
                Application.DisplayAlerts = True
                
                '最終行を取得
                lastRow = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row + 1
                ActiveSheet.Paste Destination:=Range("A" & lastRow)
                
                bookCount = bookCount + 1
                Exit For
                
            Else
                '"2020年12月"のSheetが無い場合はBookを閉じる。
                If shCount = Sheets.Count Then
                    'ファイルを閉じる
                    Application.DisplayAlerts = False
                    ActiveWorkbook.Close
                    Application.DisplayAlerts = True
                End If
            End If
        Next
        
        '初期化
        shCount = 0
        
    End If
Next

End Sub


FSOを使って、フォルダをループします。
対象のBookが見つかったらBookを開いて、Copyした後に他のBookに貼り付ける手段がわからず、Copyして強制的に閉じる(クリップボードにデータは残っている)。その後、貼り付け元のSheetをActiveSheetとして貼り付けています。これに関してはもっといい方法がありそうです。

他のBOOKへのCopy & Pasteについて

Sub copypaste()

'参考のコード
'wsT.Range("A1").CurrentRegion.Offset(offsetRow).Copy ws.Cells(outRow, 1)

Workbooks("A.xlsx").Worksheets("2020年12月").Range("A1").CurrentRegion.Copy Workbooks("40本目.xlsm").Worksheets("2020年12月").Range("A1")

End Sub

サイト管理者のコードを参考に記述してみました。
なるほど、他のBookへCopy & Pasteするときは、「Workbook.Worksheet.Range」を指定してあげないといけないのですね。
こういう基本的な部分がまだまだ甘い(;^ω^)

私の最終回答

Sub ノック40本目_2()

Const SheetName = "2020年12月"

Dim wb As Workbook: Set wb = ThisWorkbook
Dim ws As Worksheet: Set ws = wb.Worksheets(SheetName)

'書込み先データの削除
wb.Worksheets(SheetName).Cells.Clear

'FSOを宣言
Dim fso_lord As Object: Set fso_lord = CreateObject("scripting.filesystemobject")

'pathの設定
wbPath = ThisWorkbook.Path & "\40本目\data\"

'ファイルをmyfilesにSetする。
Dim myfiles As Object: Set myfiles = fso_lord.getfolder(wbPath).Files

'主処理
Dim bookCount As Integer: bookCount = 0: Dim file As Object

For Each file In myfiles
    If Not file.Name Like "~$*" Or file.Name Like ".xlsx" Then
        'ファイルを開く
        Workbooks.Open wbPath & file.Name
        
        'Sheetに”2020年12月”があるか調べる。
        For Each sh In Sheets
            shCount = shCount + 1
            shCounts = Sheets.Count
            
            'Bookが1回目の書込み処理
            If sh.Name = "2020年12月" And bookCount = 0 Then
                Worksheets(sh.Name).Select
                ActiveSheet.Range("A1").CurrentRegion.Copy ws.Range("A1")
                
                'ファイルを閉じる
                ActiveWorkbook.Close SaveChanges:=False
                
                '処理済みBook数をインクリメント
                bookCount = bookCount + 1
                Exit For
            
            'Bookが2回目以降の書込み処理
            ElseIf sh.Name = "2020年12月" And bookCount > 0 Then
                Worksheets(sh.Name).Select
                
                '最終行を取得して貼り付け
                lastRow = ws.Cells(Rows.Count, 1).End(xlUp).Row + 1
                ActiveSheet.Range("A1").CurrentRegion.Offset(1, 0).Copy ws.Range("A" & lastRow)
                
                'ファイルを閉じる
                ActiveWorkbook.Close SaveChanges:=False
                
                '処理済みBook数をインクリメント
                bookCount = bookCount + 1
                Exit For
                
            Else
                '"2020年12月"のSheetが無い場合はBookを閉じる。
                If shCount = Sheets.Count Then
                
                    'ファイルを閉じる
                    ActiveWorkbook.Close SaveChanges:=False
                End If
            End If
        Next
        
        '初期化
        shCount = 0
        
    End If
Next


End Sub


Copy、Pasteを簡潔に記述しました。変数wsにBook名とSheet名をSetしておけば、楽にPaste時に使用できます。
ファイルを閉じる処理も、「SaveChanges:=False」を加えることで、Application.DisplayAlertsをいじる必要もなくなります。

4 感想

今回もかなり勉強になりました。他のBookへCopy、Pasteする方法は知っておかないといけないですね(;^ω^)
「Range(”A1”).CurrentRegion.Offset(1, 0).Copy」で見出しを除いたデータ部をCopyする方法もかなり便利です。

ひとつ気になったのは、定数で指定している”2020年12月”は大文字の可能性もあるので、strconv関数で半角文字にしてしてあげるとよりよいのかなと思いました。


ではでは、この辺で(^^)/~~~