こんにちは! Access VBAの世界へようこそ。
現場でバリバリ動くシステムを作っていると、避けて通れないのが外部データ(Excelなど)の取り込み処理ですよね。
「`DoCmd.TransferSpreadsheet`を使えば一発じゃん!」
……そう思ってコードを書いたはいいものの、現場のユーザーが予期せぬフォーマットのExcelを放り込んできて、処理が失敗したり、裏側でこっそり「インポートエラーテーブル」が生成されて頭を抱えたりした経験はありませんか?
今回は、この「インポートエラーの自動検知と例外処理」をテーマに、プロの現場でも即座に使える堅牢な自動化テクニックを伝授します。ここをクリアすれば、あなたの作るAccessアプリは「止まらない、親切なシステム」に生まれ変わりますよ。それでは、一緒に紐解いていきましょう!
—
1. なぜ「インポートエラーテーブル」を放置してはいけないのか?
ExcelのデータをAccessに取り込むとき、`DoCmd.TransferSpreadsheet`メソッドは非常に強力です。しかし、このメソッドには「多少のデータ型の不一致やエラーがあっても、処理自体は止まらず、勝手にスキップして取り込んでしまう」というお節介な一面があります。
その際、Accessは裏側でこっそりと「〇〇_ImportErrors」といった名前のエラーテーブルを自動生成します。
[Excelファイルのインポート]
↓ 失敗データあり
[メインのテーブル] (データは入るが、不正な行は無視される)
[エラーテーブル] (「何行目のどのデータがなぜダメだったか」が記録される)
これの何が問題かというと、「ユーザーがエラーに気づかないまま、データが欠損した不完全なデータベースが完成してしまう」ということです。これでは業務上の重大なミスに繋がりかねません。
だからこそ、「インポート処理の直後にエラーテーブルの有無をVBAで監視し、もし生まれていたら即座にキャッチして、ユーザーに分かりやすく通知・ログ化する」という例外処理の仕組みが絶対に不可欠なのです。
—
2. 実装の全体像とアプローチ
今回の自動化スクリプトの心臓部は以下の3ステップです。
1. お掃除(事前準備): 過去に残った古いエラーテーブルをあらかじめ削除しておく。
2. インポート実行: `DoCmd.TransferSpreadsheet`を実行する。
3. 監査と例外処理(事後監視): カレントデータベースのテーブル一覧を走査し、エラーテーブルが生成されたかどうかを判定する。あれば中身を読み取ってログを出力!
特に3番目の「テーブルの存在確認」において、Accessオブジェクトモデルの真髄である `CurrentDb.TableDefs` を使いこなすのが、ワンランク上のエンジニアへの第一歩です。
—
3. 実装コード:インポート監視&例外処理の完全版
それでは、そのままコピペして開発現場で使える実用的なVBAコードを公開します。標準モジュールに貼り付けてお使いください。
Option Compare Database
Option Explicit
‘ =========================================================================
‘ 処理名 : SafeImportExcelWithErrorHandler
‘ 概要 : Excelを取り込み、インポートエラーを自動監視・例外処理するプロシージャ
‘ =========================================================================
Public Sub SafeImportExcelWithErrorHandler()
On Error GoTo ErrorHandler ‘ 予期せぬVBA自体のエラーを捕捉するため
Dim targetTbl As String
Dim excelPath As String
Dim errorTblName As String
Dim tdf As TableDef
Dim isErrorGenerated As Boolean
‘ — 設定エリア —
targetTbl = “T_売上データ” 3’ 取り込み先のテーブル名
excelPath = CurrentProject.Path & “\sales.xlsx” ‘ 取り込むExcelファイルのパス
errorTblName = targetTbl & “$_ImportErrors” ‘ Accessが自動生成するエラーテーブル名の規則
‘ ————————————————————-
‘ Step 1: 事前準備(過去に残っている同名のエラーテーブルを消去)
‘ ————————————————————-
Call DropTableIfExists(errorTblName)
‘ ————————————————————-
‘ Step 2: インポートの実行
‘ ————————————————————-
‘ 第3引数は True にすることで、Excelの1行目をフィールド名として認識させます
DoCmd.TransferSpreadsheet acImport, acSpreadsheetTypeExcel12Xml, _
targetTbl, excelPath, True
‘ ————————————————————-
‘ Step 3: インポートエラーの自動監視(例外処理の核心)
‘ ————————————————————-
isErrorGenerated = False
‘ CurrentDb.TableDefs をループして、エラーテーブルが生成されたかチェック
For Each tdf In CurrentDb.TableDefs
If tdf.Name = errorTblName Then
isErrorGenerated = True
Exit For
End If
Next tdf
‘ — 判定とユーザーへの通知 —
If isErrorGenerated Then
‘ 異常系:エラーテーブルが存在する場合
MsgBox “【警告】データの取り込み時に一部のエラーが発生しました!” & vbCrLf & _
“不正なデータはスキップされています。ログを確認してください。”, _
vbExclamation, “インポート例外検知”
‘ ここでエラーテーブルの中身を集計したり、別ログへ吐き出す処理を呼び出せます
Call AnalyzeImportErrors(errorTblName)
Else
‘ 正常系
MsgBox “Excelデータの取り込みが正常に完了しました。”, vbInformation, “完了”
End If
Exit Sub
ErrorHandler:
‘ VBA実行時自体のエラー(ファイルが存在しない、排他制御がかかっている等)
MsgBox “システムエラーが発生しました。” & vbCrLf & _
“エラー番号: ” & Err.Number & vbCrLf & _
“内容: ” & Err.Description, vbCritical, “致命的エラー”
End Sub
‘ =========================================================================
‘ 補助プロシージャ : 指定したテーブルが存在すれば安全に削除する
‘ =========================================================================
Private Sub DropTableIfExists(ByVal tblName As String)
Dim tdf As TableDef
On Error Resume Next
Set tdf = CurrentDb.TableDefs(tblName)
If Err.Number = 0 Then
‘ テーブルが存在する場合は削除
DoCmd.DeleteObject acTable, tblName
End If
On Error GoTo 0
End Sub
‘ =========================================================================
‘ 補助プロシージャ : エラー内容をイミディエイトウィンドウに出力(ログ化の例)
‘ =========================================================================
Private Sub AnalyzeImportErrors(ByVal errTbl As String)
Dim db As DAO.Database
Dim rs As DAO.Recordset
Set db = CurrentDb
Set rs = db.OpenRecordset(errTbl, dbOpenSnapshot)
Debug.Print “=== インポートエラーログ (” & Now & “) ===”
‘ エラーテーブルの中身を読み取ってログ出力(実務ではテキスト出力や別テーブル保存に応用可能)
Do Until rs.EOF
Debug.Print “行番号: ” & rs.Fields(“ErrorRow”).Value & _
” / フィールド: ” & rs.Fields(“FieldName”).Value & _
” / 理由: ” & rs.Fields(“Description”).Value
rs.MoveNext
Loop
rs.Close
Set rs = Nothing
Set db = Nothing
‘ ※実務では、ここでユーザー向けに「エラー詳細レポート」のフォームを開くなどの親切設計を入れます
End Sub
—
4. コードの解説と「知っておくべきポイント」
このコードには、Access VBAを極めるためのエッセンスが詰まっています。いくつか重要なポイントを解説します。
① `CurrentDb.TableDefs` による厳密なオブジェクト監視
Access初学者の頃は、テーブルの存在確認を「エラートラップ(`On Error Resume Next`)」に頼りがちです。しかし、プロのアーキテクトはコレクションの走査(ループ)やメタデータの直接参照を好みます。
今回は `CurrentDb.TableDefs` を全件チェックし、「Excelが勝手に作ったエラーテーブルの名称規則」と一致するものがあるかをプログラム的に確実に検知しています。これにより、曖昧さのない堅牢な判定が可能になります。
② 正常系と異常系の完全な分離
`DoCmd.TransferSpreadsheet` 自体はエラーを出さずに進むため、従来のコードだと「取り込めたからOK」と勘違いしがちでした。しかしこのコードでは、インポートが終わった後に「本当にデータが綺麗に入ったか」の健康診断(監査)をワンクッション挟む設計にしています。これが例外処理の美学です。
③ DAOによるエラーテーブルの読込 (`AnalyzeImportErrors`)
エラーテーブルが生成された場合、その中には「何行目でコケたか (`ErrorRow`)」「どの列か (`FieldName`)」「なぜダメだったか (`Description`)」という宝の山(ログ)が眠っています。これをDAO (`OpenRecordset`) で読み込み、イミディエイトウィンドウ(またはファイルや別テーブル)に吐き出すことで、トラブルシューティングの時間を劇的に短縮できます。
—
5. まとめ
いかがでしたでしょうか?
今回は、`DoCmd.TransferSpreadsheet` の裏でひっそり生成される「インポートエラーテーブル」を自動監視し、例外処理をエレガントに自動化する手法を解説しました。
ここをクリアすれば、マクロの記録をポチポチ押していたレベルから、「業務の安定稼働を守るプロフェッショナルなVBAエンジニア」へと確実にステップアップできます。
現場のユーザーから「なんかこのシステム、エラーが出たらちゃんと教えてくれるから安心して使えるよ!」と言われる瞬間は、エンジニアにとって最高のご褒美です。ぜひ、あなたのAccessアプリにもこの仕組みを取り入れてみてくださいね。
ここをクリアできたら、Access VBAの基本はもうバッチリです! 次のステップへ向かって、一緒にコードを書いていきましょう。
