○ 複数のファイルからデータを収集、Excelの表1つにまとめよう。
契約月ごとに別のシートを作成し、データを分割しよう。
マクロで作成した図5(前編に掲載)の一覧表シートをもう一度見てください。この表には、さまざまな契約日のデータが混在しています。この表を契約した月ごとのデータに分割し、別のシートにコピーできると便利です。
このように、一覧表のデータをある項目で分割し、別のシートにコピーして利用したいというケースは、業務の中で頻繁に発生します。Excelマクロは、これらの作業もかんたんに自動化でき、業務の効率化を図る力強い味方になってくれます。早速、作っていきましょう。
標準モジュールに、続けて、画1 のコードを記述してください。
(1)の「Application.DisplayAlerts = False」は、ダイアログの表示を抑制します。(2)~(4)の処理でワークシートを削除するときに確認のダイアログボックスが表示されるのですが、これを最初に抑制しておきます。
(2)のFor Each…Nextステートメントでは、サンプルブックにあるすべてのワークシートに対して、処理を繰り返します。繰り返し処理の間は、変数oをWorksheetオブジェクトとして扱えます。
(3)のIfステートメントの条件式「o.Name <> "一覧表"」で、シート名が「一覧表」以外のすべてのシートを、
(4)で削除(o.Delete)します。マクロを繰り返して実行するときに、前回の実行結果(追加されたシート)が残っていると、シート名が重複してエラーになります。そこで、契約月別のシートを作成する前に、一覧表シート以外のすべてのシートを削除しておきます。
(5)の「er = Cells(Rows.Count, 1).End(xlUp).Row」で、一覧表シートのデータのある最終行番号を変数erに格納します。
(6)は、行継続文字「半角スペース」+「_(半角アンダーバー)」を使用して改行していますが、実際は1行のコードです。一覧表シートのデータのあるセル範囲(Range(Cells(3, 1), Cells(er, 5)).Sort)を対象に、Sortメソッドで並べ替えを行います。そのとき、キーになるのはE列(Key1:=Cells(3, 5))の契約日です。並べ替えの順序は昇順(Order1:=xlAscending)にしています。
(7)のFor…Nextステートメントでは、カウンタ変数iの開始値を「3」、終了値をデータのある最終行番号(サンプルブックでは22行目)としています。
(8)のWithステートメントでは、「Worksheets("一覧表")」と、サンプルブックの一覧表シートを指定しています。このあと「End With」が記述されるまでの間、「.(ピリオド)」で始まる箇所はすべて、一覧表シートに対する命令になります。
(9)の「y = Year(.Cells(i, 5).Value)」では、Year関数を使用してE列の契約日から年を取得し、変数yに格納します。
同様に(10)の「m = Month(.Cells(i, 5).Value)」は、契約日から月を取得し、変数mに格納しています。
(11)のIfステートメントでは、条件式「m <> Month(.Cells(i + 1, 5).Value)」によって、現在繰り返し対象となっている行のE列の契約月(m)と、次行の契約月(Month(.Cells(i + 1, 5).Value))を比較し、
月が異なるときに(12)~(17)の処理を実行します。E列は昇順に並べ替えが行われているので、条件を満たすときは、次行から契約月が異なるデータが入力されているということがわかります。
(11)の条件が満たされるとき、
(12)で一覧表シートをコピー(.Copy)します。貼り付け先は、シート見出しの右端(After:=Sheets(Sheets.Count))です。コピーして貼り付けられたシートは常にアクティブシートになります。
(13)で、このアクティブシートのシート名(ActiveSheet.Name)を、契約年月(Format(DateSerial(y, m, 1), "yyyy年m月"))に変更しています。Format関数は、指定した書式に文字列を整形して返す関数です。また、DateSerial関数は、引数に指定した年、月、日に対応する日付を返す関数です。ここでは、「変数y年、変数m月、1日」の日付を、「"yyyy年m月"」の書式に整形し、シート名に設定します。
(14)の「Cells.ClearContents」で、コピーしたシートのすべてのデータをクリアし、レイアウトのみを利用します。
(15)で、一覧表シートのE列にオートフィルターを設定(.Range("A2").AutoFilter 5)します。絞り込みの対象となるのは、契約月の1日から(">=" & DateSerial(y, m, 1))、契約月の末日まで("<=" & DateSerial(y, m + 1, 0))にあるデータです。開始日には、DateSerial関数を使って、「変数y年、変数m月、1日」の日付を指定します。終了日には、「変数y年、変数m+1月、0日」と、「開始日翌月の0日」を指定しています。ですが「0日」という日付は存在しませんので、この場合、DateSerial関数では「変数y年、変数m月の末日」の日付が終了日に設定されます。
(16)では、(15)で絞り込んだ一覧表シートのデータを、(12)で作成したシート(ActiveSheet.Range("A1"))にコピー(.Copy)します。コピーの対象となるセル範囲は、一覧表シートのA1セルから始まるアクティブセル領域(.Range("A1").CurrentRegion)です。アクティブセル領域とは、空白行と空白列で囲まれたセル範囲を指します。
(17)では、(15)で設定した一覧表シートのオートフィルターを解除(.Range("A2").AutoFilter)しています。オートフィルターを解除するには、このように同じセル範囲に対してもう一度AutoFilterメソッドを実行します。
(7)~(17)の処理を、一覧表シートのすべてのデータに対して繰り返すことで、契約月が異なるデータをそれぞれの契約月のシートにコピー、分割することができます。
では実際に、コードを実行して動作を確認してみましょう。サンプルブックの一覧表シートがアクティブな状態で、マクロを実行します。
「マクロ」ダイアログボックスを表示し、「マクロ名」の一覧から、「月別シート作成」マクロを選択し、「実行」ボタンをクリックします。
サンプルブックに「2023年1月」「2023年2月」「2023年3月」の3つのシートが追加されました(画2)。
追加された各シートを確認してください。契約月ごとにデータが分割され、コピーされています。
サンプルでは3カ月分の契約データしか用意していませんが、さらに契約月の数が増えても、同様に、シートの追加とデータの分割を実行します。試してみてください。
ちなみに今回のサンプルは、契約書が1年以上発行されないような特殊なケース(2023年3月の次の契約が2024年3月になるなど)は想定していません。そのようなケースを想定する場合は、リスト2の(11)のIfステートメントを、リスト3のように変更してください。
画3、では、E列の契約日をFormat関数で「yyyymm」の書式に整形し、年月を比較しています。このようにすることで、2023年3月の次の契約が2024年3月になるなどの特殊なケースに対応することができます。
今回のマクロ、いかがでしたでしょうか? 複数のファイルから必要な情報を集め、1つの表に取りまとめるという作業は、業務のいたるところで発生します。Excelファイルで作成された書類は、マクロを使って簡単に情報を取得し、ユーザーが求めるExcelファイルの表に転記することが可能です。書類の作成にExcelを利用することで、業務効率化できる典型のモデルです。皆さんの会社でも似たような業務がないか、ぜひ探してみてくださいね。