VBAで複数のシートに同じ形式のデータがあるExcelファイルを、1つのシートにデータを行方向へまとめる方法から、最大行を超えた場合の処理方法をご説明します。
シートが年や各月で分かれている場合に、全データで集計したいときにどうしても1つのシートにまとめたくなることがあります。
そんな時のためのひな形を一つ用意しておくだけで、簡単に複数のシートに分かれているデータを1つのシートにまとめる事ができます。
もしExcelの最大行を超えるようなデータの場合は、エラーとなるため最大行を超える結合が発生した場合の対処法も記載したいと思います。
複数ファイルのデータをまとめる方法や、サブフォルダのすべてのファイルをまとめる方法については、下記記事をご覧ください。
1.複数シートのデータを1シートにまとめる方法
複数のシートに同じ形式が存在する場合、1つのシートにまとめるためには次のような方法でまとめていきます。
まずはまとめるためのシートを作成します。
まとめるためのシートを作成したら、次はデータのあるシートのデータを格納します。
データを格納したらまとめるシートの最終行に貼り付けます。
これをシート数分繰り返すだけです。
注意点はExcelの最大行を超える連結を行おうとした場合、エラーとなります。
また、Excelはセルへの出力がとても遅いため、各シートのデータをすべて配列に格納してからまとめるシートへ出力しようとした場合も注意が必要です。
それはメモリー不足のエラーが発生する可能性です。
Excelの配列は無限に領域を確保できるわけではないため、いつかはメモリー不足になります。
そのため、よほど処理速度にこだわらない限りは1シートずつ格納と出力を行った方が良いです。
2.サンプルコード
さっそくサンプルコードです。
次のように1月~12月というシートがあり、それぞれに「日付」「価格」「販売個数」「売上」といったデータが日数分存在します。
これらのデータを1つのシートにまとめる処理を行います。
Option Explicit
Dim i As Long
Dim r As Long
Dim s As Long
Dim Sh As Worksheet
Dim MaxRow As Long
Dim MaxCol As Long
Dim MyArray As Variant
Dim JoinSh As Worksheet
Dim n As Long
Dim shcount As Long
Application.DisplayAlerts = False 'シート削除時のアラート停止
For Each Sh In Worksheets
If InStr(Sh.Name, "統合") <> 0 Then Sh.Delete 'すでに統合シートが存在する場合は一旦削除
Next
Application.DisplayAlerts = True 'シート削除時のアラート停止を解除
shcount = Worksheets.Count
s = 1 '最大行を超えた場合次の統合シートを作成するための番号
Worksheets.Add after:=Worksheets(shcount) '新規に統合シートを追加
ActiveSheet.Name = "統合"
Set JoinSh = ActiveSheet '統合シートを変数に格納
For i = 1 To shcount 'シートを統合シートの次~末尾までループ
With Worksheets(i) '各月シート
Debug.Print .Name
If i = 2 Then
r = 1 '最初だけ項目も取得
Else
r = 2 '最初以外は2行目から取得
End If
MaxRow = .Cells(Rows.Count, 1).End(xlUp).Row '1列目で最終行を取得
MaxCol = .Cells(1, Columns.Count).End(xlToLeft).Column '1行目で最終列を取得
MyArray = Range(.Cells(r, 1), .Cells(MaxRow, MaxCol)) 'A1~データ末尾まで配列に格納
End With
With JoinSh '統合シート
MaxRow = .Cells(Rows.Count, 1).End(xlUp).Row '統合シートの1列目で最終行取得
If MaxRow + UBound(MyArray) > Rows.Count Then '最大行を超える場合の処理
s = s + 1 '統合シートの番号を加算
Worksheets.Add after:=Worksheets(Worksheets.Count) '新規に統合シートを追加
ActiveSheet.Name = "統合" & s '名前が同じにならないように番号を追加
Set JoinSh = ActiveSheet '統合シートを変数に格納
MaxRow = JoinSh.Cells(Rows.Count, 1).End(xlUp).Row '統合シートの1列目で最終行取得
End If
If JoinSh.Cells(1, 1) = "" Then
'最初だけ1行目から貼り付け
Range(JoinSh.Cells(1, 1), JoinSh.Cells(UBound(MyArray), MaxCol)) = MyArray
Else
'最初以外は最終行の次に貼り付け
Range(JoinSh.Cells(MaxRow + 1, 1), JoinSh.Cells(MaxRow + UBound(MyArray), MaxCol)) = MyArray
End If
End With
Next i
End Sub
コードの説明
基本的にはコード内に説明のコメントを記述していますが、簡単に説明します。
統合シートの確認
まずはまとめるためのシートを作る前に、存在していないか確認します。
すでに存在している場合は同じ名前のシートを追加しようとするとエラーとなるためです。
シートを削除する場合にはアラートが表示されてしまいますので、「Application.DisplayAlerts = False」でアラートを表示しない設定にしています。
「For Each Sh In Worksheets」~「Next」でシートをループして、「If Sh.Name = “統合” Then Sh.Delete」の部分で「統合」シートがあれば削除しています。
新規で統合シートの追加
「s = 1」は統合シートを追加する数です。
最大行を超えた場合の対策です。
「Worksheets.Add Before:=Worksheets(s) 」で新規に統合シートを追加して、「ActiveSheet.Name = “統合”」で名前を統合に指定します。
「Set JoinSh = ActiveSheet」で追加した統合シートを変数へ格納しています。
各シートのデータを取得
「For i = 1 To shcount」で統合シートの次のシートから末尾のシートまでループします。
「With Worksheets(i)」でループしたシートをWithでくくります。
「r = 1」と「r = 2」に関しては1行目の項目を最初だけ取得したいために、配列へ格納する範囲を1行目からか2行目からか分岐させるためです。
「MyArray = Range(.Cells(r, 1), .Cells(MaxRow, MaxCol))」で指定しているシートのデータを配列に格納しています。
最大行を超える判定
「If MaxRow + UBound(MyArray) > Rows.Count Then」で貼り付ける領域が最大行を変えるか判定しています。
超えた場合は「s」を加算して新たに統合シートを追加します。
統合シートへデータを貼り付け
「With JoinSh」で先ほど新規に追加した統合シートでくくります。
「If .Cells(1, 1) = “” Then」で1行目が空白の場合は1行目から貼り付けるための分岐です。
「Range(.Cells(1, 1), .Cells(UBound(MyArray), MaxCol)) = MyArray」で配列を統合シートへ貼り付けますが、必ず配列の領域と貼り付けるセルの範囲は一緒になるように指定します。
「Range(.Cells(MaxRow + 1, 1), .Cells(MaxRow + UBound(MyArray), MaxCol)) = MyArray」が少し複雑です。
赤字の「MaxRow + 1」は最終行の次の行を指定しています。
青字の「MaxRow + UBound(MyArray)」の部分は最終行+配列の領域(行数)を加算した行数を指定してます。
最終行からスタートして、配列の行数分加算した行まで貼り付けるためです。
以上で複数のシートのデータを1つのシートへまとめる処理となります。
試しに最大行を超えるだけループしてみる
今回使用したデータでは最大行を超えないため、検証用に大きなデータを用意して意図的に最大行を超えさせてみました。
無事統合2シートが作成されて146万行分のデータが連結されました。