Excelの複数のファイルにレコードを、1つのファイルにマージするためのVBAを作成しました。
「営業担当者ごとの今月の受注データをひとつにまとめて、部全体の受注データを作成する」といった作業を行う場合、ファイルをひとつずつ開いてコピペするのは地味に面倒な作業です。
仮に「ひとつのファイルを開く⇒コピペする⇒ファイルを閉じる」の一連の作業に1分かかるとして、10人分だと10分、100人分だと100分もかかる作業です。
単純な作業は自動化しましょう。
- Excelの複数ファイルを自動集計できる。
完成形
以下が完成形です。詳細はのちほど解説します。
Public Const SHEET_FROM = "Sheet1" ' マージするデータが保存されているシート名
Public Const SHEET_TO = "マージ後" ' マージ後のデータを保存するシート名
Public COLUMN_END As Long ' 最大カラム数
Public Function MergerFiles()
Dim File As String
COLUMN_END = Columns.Count
' マージする対象のファイルの場所
FILE_PATH = ThisWorkbook.Path
FILE_PATH_FROM = FILE_PATH & "\From"
' ヘッダから下のデータをクリア
ThisWorkbook.Sheets(SHEET_TO).Range(Cells(2, 1), Cells(Rows.Count, COLUMN_END)).Clear
' ファイルがあるだけループ
File = Dir(FILE_PATH_FROM & "\*.xlsx")
Do While File <> ""
MergeFile Path:=FILE_PATH_FROM & "\" & File
File = Dir()
Loop
End Function
Private Function MergeFile(Path As String)
Dim BookFrom As Workbook
Set BookFrom = Workbooks.Open(Filename:=Path, ReadOnly:=True, UpdateLinks:=False)
Set SheetFrom = BookFrom.Sheets(SHEET_FROM)
Set SheetTo = ThisWorkbook.Sheets(SHEET_TO)
' マージ元の行数(ヘッダを含む)
With SheetFrom
RowsFrom = .Cells(.Rows.Count, 1).End(xlUp).Row
End With
' マージ先の行数(ヘッダを含む)
With SheetTo
RowsTo = .Cells(.Rows.Count, 1).End(xlUp).Row
End With
' コピー元の範囲(ヘッダの次の行から最後の行まで)
Set RangeFrom = SheetFrom.Range(SheetFrom.Cells(2, 1), SheetFrom.Cells(RowsFrom, COLUMN_END))
' コピー先の範囲(最終行の次の行から、コピー元の行数分)
Set RangeTo = SheetTo.Range(SheetTo.Cells(RowsTo + 1, 1), SheetTo.Cells(RowsTo + RowsFrom - 1, COLUMN_END))
RangeTo.Value = RangeFrom.Value
BookFrom.Close SaveChanges:=False
End Function
解説
VBAの中で分かりにくそうな箇所を解説します。
ヘッダから下のデータをクリア
' ヘッダから下のデータをクリア
ThisWorkbook.Sheets(SHEET_TO).Range(Cells(2, 1), Cells(Rows.Count, COLUMN_END)).Clear
ここでは、マージ後のデータ格納領域のクリアを行っています。
「Range(Cells(2, 1), Cells(Rows.Count, COLUMN_END))」が、クリア対象となる領域です。ヘッダ行の次の行である2行目から、データが格納されている最終行までを指しています。
下図を例にすると、Cells(2,1)はA2のセル、Cells(Rows.Count, COLUMN_END)は、4行目の右端のセルを表しています。
行数
' マージ元の行数(ヘッダを含む)
With SheetFrom
RowsFrom = .Cells(.Rows.Count, 1).End(xlUp).Row
End With
' マージ先の行数(ヘッダを含む)
With SheetTo
RowsTo = .Cells(.Rows.Count, 1).End(xlUp).Row
End With
コピペをするには「コピー元の行数」と「貼り付け先の最初の行の位置」の情報が必要になります。
上記では、A列の一番下のセルから「Ctrl+↑」で最終行に移動する要領で、コピー元・貼り付け先それぞれのヘッダ行を含む行数(最終行の行番号)を取得しています。
貼り付け
' コピー元の範囲(ヘッダの次の行から最後の行まで)
Set RangeFrom = SheetFrom.Range(SheetFrom.Cells(2, 1), SheetFrom.Cells(RowsFrom, COLUMN_END))
' コピー先の範囲(最終行の次の行から、コピー元の行数分)
Set RangeTo = SheetTo.Range(SheetTo.Cells(RowsTo + 1, 1), SheetTo.Cells(RowsTo + RowsFrom - 1, COLUMN_END))
RangeTo.Value = RangeFrom.Value
コピペを一括で行っています。
For文などで1行ずつコピーして貼り付ける方法もありますが、その方法だと時間がかかりすぎるため、コピーする範囲を一括選択して貼り付けるようにしています。
下図を例にすると、コピー元の行数が3行であるため、貼り付け先の領域は4~6行目になります。
まとめ
今回紹介した内容は、コピペに最低限必要な部分を記載しました。
必要に応じて、マージボタンを追加したり、コピー元のファイルのオープン・クローズを見せないようにしたり、カスタイマイズしていただければと思います。
参考になればうれしいです。
コメント