【エクセルVBA入門】エラーが発生したときに分岐処理を追加する方法


alert

photo credit: kolix incomplete walk via photopin (license)

みなさん、こんにちは!
タカハシ(@ntakahashi0505)です。

エクセルVBAでバラバラの経費精算書ファイルのデータを収集するマクロの作り方をお伝えしています。

前回の記事はコチラ。

【エクセルVBA入門】Vlookupメソッドを使ったときに発生するエラーを回避する方法
エクセルVBAでバラバラの経費精算書を一つのデータベースにまとめるマクロの作り方についてお伝えしています。今回はVLookupメソッドを使ったときに発生するエラーを回避する方法についてお伝えします。

VLookupメソッドが失敗しても処理を継続するためにOn Error Resume Nextステートメントを追加しました。

ただ、エラーが発生したことがわかりづらくなっちゃったんですよね。

ということで、今回はエクセルVBAでエラーが発生したときにメッセージを表示する処理を追加する方法をお伝えしていきます。

では、行ってみましょう!

スポンサーリンク

前回のおさらい

前回作成したコードはコチラです。

Sub 経費精算データ取り込み()

Dim fso As FileSystemObject
Set fso = New FileSystemObject

Dim di As Long: di = wsData.Cells(Rows.Count, 1).End(xlUp).Row + 1
Dim f As File
For Each f In fso.GetFolder(ThisWorkbook.Path & "\data").Files
    With Workbooks.Open(f.Path)
        With .Worksheets(1)
            
            Dim period As String: period = Left(f.Name, 6)
            Dim month As Date: month = DateSerial(Left(period, 4), Right(period, 2), 1)
                                    
            On Error Resume Next
            Dim staffId As Long: staffId = Val(Right(Replace(f.Name, ".xlsx", ""), 4))
            Dim staffName As String: staffName = WorksheetFunction.VLookup(staffId, wsStaff.Range("A:D"), 2, False)
            Dim departmentId As Long: departmentId = WorksheetFunction.VLookup(staffId, wsStaff.Range("A:D"), 3, False)
            Dim departmentName As String: departmentName = WorksheetFunction.VLookup(staffId, wsStaff.Range("A:D"), 4, False)
                      
            Dim i As Long: i = 12
            Do While .Cells(i, 1).Value <> ""
                wsData.Cells(di, 1).Value = month '1 対象月
                wsData.Cells(di, 2).Value = .Cells(i, 1).Value '2 日付
                wsData.Cells(di, 3).Value = departmentId  '3 部署No
                wsData.Cells(di, 4).Value = departmentName '4 部署
                wsData.Cells(di, 5).Value = staffId '5 社員No
                wsData.Cells(di, 6).Value = staffName '6 氏名
                wsData.Cells(di, 7).Value = .Cells(i, 2).Value '7 科目
                wsData.Cells(di, 8).Value = .Cells(i, 5).Value '8 摘要
                wsData.Cells(di, 9).Value = .Cells(i, 6).Value '9 金額
                wsData.Cells(di, 10).Value = .Cells(i, 7).Value '10 備考
                i = i + 1: di = di + 1
            Loop
        End With
        .Close
    End With
Next f

End Sub

15行目にOn Error Resume Nextステートメントを入れたことで、その後のVLookupメソッドが失敗したとしても、処理を続行するようになりました。

ただ、その場合の結果がコチラですね。

On Error Resume Nextで実行した結果

正しくないデータが入ってしまいました。

もっとエラーが発生したことがわかるようにしたいですよね。

Errオブジェクトとは

そんな時のためにErrオブジェクトを使って、もう少しエラーが発生したことをわかりやすくしてあげましょう。

Errオブジェクトには、エラーが発生したときにどんなエラーが発生したのかという情報が格納されます。

これを使ってエラーが発生したときに何らかのアクションを起こすという処理を追加することができます。

Numberプロパティを使ってエラーの発生で分岐

ErrオブジェクトのNumberプロパティには初期値は0が格納されていて、エラーが発生するとエラーの種類に応じて0より大きい番号が格納されます。

Errオブジェクト.Number

例えば、以下のエラーメッセージであれば「1004」がエラーの番号になります。

実行時エラーの番号

ですから例えば、以下のようなコードを挿入すると

If Err.Number <> 0 Then
    MsgBox f.Name & " の処理でエラーが発生しました。"
End If

それ以前にエラーが発生していれば、メッセージダイアログが表示されます。

On Error GoTo 0でエラーハンドラーを無効化する

しかし、一点問題がありまして、On Error Resume Nextステートメントは、VLookupメソッド以外のエラーについても継続をしてしまいます。

想定していないエラーまで、全てもみ消してしまうわけです。

それはそれで問題ですので、On Error GoTo 0ステートメントで、エラーハンドラーを無効化します。

On Error GoTo 0

「エラーが発生したら0行目に飛ぶ」、みたいな命令に見えますが、そうではなくて

  • On Error~で有効になっているエラーハンドラーを無効化する
  • Errオブジェクトを初期化する

という役割を果たします。

つまり、今回の場合は、On Error Resume Nextの効果をかき消して、さらにErrオブジェクトをリセット(Numberプロパティも0に)することになります。

エラー処理を加えた経費精算データ収集マクロ

以上を踏まえたコードはこちらになります。

Sub 経費精算データ取り込み()

Dim fso As FileSystemObject
Set fso = New FileSystemObject

Dim di As Long: di = wsData.Cells(Rows.Count, 1).End(xlUp).Row + 1
Dim f As File
For Each f In fso.GetFolder(ThisWorkbook.Path & "\data").Files
    With Workbooks.Open(f.Path)
        With .Worksheets(1)
            
            Dim period As String: period = Left(f.Name, 6)
            Dim month As Date: month = DateSerial(Left(period, 4), Right(period, 2), 1)
                                    
            On Error Resume Next
            Dim staffId As Long: staffId = Val(Right(Replace(f.Name, ".xlsx", ""), 4))
            Dim staffName As String: staffName = WorksheetFunction.VLookup(staffId, wsStaff.Range("A:D"), 2, False)
            Dim departmentId As Long: departmentId = WorksheetFunction.VLookup(staffId, wsStaff.Range("A:D"), 3, False)
            Dim departmentName As String: departmentName = WorksheetFunction.VLookup(staffId, wsStaff.Range("A:D"), 4, False)

            If Err.Number <> 0 Then
                MsgBox f.Name & " の処理でエラーが発生しました。"
                staffId = 0
                staffName = ""
                departmentId = 0
                departmentName = ""
            End If
            On Error GoTo 0
                      
            Dim i As Long: i = 12
            Do While .Cells(i, 1).Value <> ""
                wsData.Cells(di, 1).Value = month '1 対象月
                wsData.Cells(di, 2).Value = .Cells(i, 1).Value '2 日付
                wsData.Cells(di, 3).Value = departmentId  '3 部署No
                wsData.Cells(di, 4).Value = departmentName '4 部署
                wsData.Cells(di, 5).Value = staffId '5 社員No
                wsData.Cells(di, 6).Value = staffName '6 氏名
                wsData.Cells(di, 7).Value = .Cells(i, 2).Value '7 科目
                wsData.Cells(di, 8).Value = .Cells(i, 5).Value '8 摘要
                wsData.Cells(di, 9).Value = .Cells(i, 6).Value '9 金額
                wsData.Cells(di, 10).Value = .Cells(i, 7).Value '10 備考
                i = i + 1: di = di + 1
            Loop
        End With
        .Close
    End With
Next f

End Sub

21~28行目が追加した処理ですね。

実行時エラーが発生したときに、メッセージの表示に加えて、マスタから取得すべきデータを0または空にしています。

エラーが発生した場合、以下のようなメッセージが表示されつつ

実行時エラーが発生したときに表示されるメッセージ

実行結果は以下のように、余計なデータが含まれないようになります。

経費精算書マクロの実行結果

まとめ

以上、エクセルVBAでエラーが発生したときに分岐処理を追加する方法についてお伝えしました。

On Errorステートメントと分岐処理について解説をしました。

これで、ファイル名にミスがあっても拾えるようになりましたが、他にも色々なパターンがありますので、ベストな方法を模索してみてくださいね。

次回は、別のエラー発生要因について考えてみたいと思います

【エクセルVBA入門】オートフィルタや行の非表示で隠れている行を全て表示する
エクセルVBAでバラバラの経費精算書のデータを収集するマクロの作り方をお伝えしています。今回はオートフィルタを解除する方法と、行の非表示で隠れている行を表示する方法についてそれぞれお伝えしていきます。

どうぞお楽しみに!

連載目次:エクセルVBAで経費データをデータベースに集約する

請求書シリーズと逆のパターンですが、バラバラの帳票からデータ一覧つまりデータベースに情報を集めて蓄積していく、というお仕事も多いと思います。ここでは各担当者から提出された経費精算書をデータベースに蓄積するプログラムを目標にして進めていきます。
  1. 【エクセルVBA入門】バラバラの経費精算書をデータにまとめる
  2. 【エクセルVBA入門】Do While~Loop文で条件を満たす間繰り返し
  3. 【エクセルVBA入門】繰り返しを使ってデータの転記をするときの2つのポイント
  4. 【エクセルVBA入門】With文でプログラムをスッキリわかりやすく書く
  5. 【エクセルVBA入門】他のワークブックをWithで開く&保存せずに閉じる
  6. 【エクセルVBA入門】フォルダやファイルを操作するFileSystemオブジェクトとその使い方
  7. 【エクセルVBA入門】For Each~Next文でフォルダ内のブック全てを開く方法
  8. 【エクセルVBA入門】シートのデータがある最終行番号を求めるステートメントを徹底解説
  9. 【エクセルVBA入門】開いたブック名から文字列を抽出して人為的なミスを回避する方法
  10. 【エクセルVBA入門】マクロを作るときに知っておきたいマスタデータのこと
  11. 【エクセルVBA入門】開いたブックのファイル名から番号を取り出して数値に変換する
  12. 【エクセルVBA入門】マクロでVlookupを使ってデータを検索する方法
  13. 【エクセルVBA入門】Vlookupメソッドを使ったときに発生するエラーを回避する方法
  14. 【エクセルVBA入門】エラーが発生したときに分岐処理を追加する方法
  15. 【エクセルVBA入門】オートフィルタや行の非表示で隠れている行を全て表示する

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