【実務・中級編】【中級】Application.CurrentData.AllTablesを使用した、存在しないテーブルへのアクセス回避 – Access VBA解析バイブル

スポンサーリンク

Access開発における「テーブル存在チェック」のパラダイムシフト

現場のAccess開発で、最も無駄なデバッグ工数を奪う原因の一つを知っているか?
それは、「存在しないテーブルやクエリにアクセスして走る実行時エラー(トラップ可能なエラー 3078)」だ。

「とりあえずエラーハンドリング(`On Error Resume Next`)を入れておけばいいや」
――もし君がそう考えているなら、今すぐその甘い設計を捨ててほしい。

エラーを発生させてから `Err.Number = 3078` をキャッチするアプローチは、VBAの実行コンテキストにおいて極めて重いオーバーヘッドを伴う。さらに、予期せぬエラーまで握りつぶしてしまうリスクを孕んだ、極めて場当たり的なコーディングだ。

プロフェッショナルなエンジニアが目指すべきは、エラーを「事後処理」することではなく、「事前に防ぐ(防御的プログラミング)」ことである。
今回は、`Application.CurrentData.AllTables` コレクションを駆使し、Accessの内部メタデータを一瞬で参照してスマートに分岐する、極限まで洗練されたテーブル存在確認のアーキテクチャを伝授する。

なぜ `CurrentDb.TableDefs` ではなく `CurrentData.AllTables` なのか?

Access VBAでテーブルの存在を確認する際、古い教科書やネットのサンプルでは `CurrentDb.TableDefs` をループさせたり、存在しない名前を指定してエラーをトラップする方法が紹介されている。

しかし、これは以下の理由から現代のエンタープライズ開発ではアンチパターンだ。

1. パフォーマンスの劣化: `TableDefs` はDAO(Data Access Objects)のコレクションであり、ローカルテーブルだけでなくリンクテーブルやシステムテーブルの定義情報までメモリ上にロードするため、重い。
2. オブジェクトモデルの不一致: 現代のAccessはADO/ACEDAOが混在する環境であり、ナビゲーションウインドウ(UI)に表示されるテーブル群の状態をストレートに取得するには、AcObjectTypeに対応した `CurrentData` オブジェクトを使うのが最もオブジェクト指向的かつ軽量である。

`Application.CurrentData.AllTables` は、Accessデータベース内のすべてのテーブル(ローカルおよびリンク)のメタデータを格納するコレクションだ。これを利用すれば、データベースエンジンに負荷をかけず、メモリ上でミリ秒単位のテーブル存在チェックが可能となる。

プロダクションコード:堅牢なテーブル存在チェック関数

現場でそのままコピー&ペーストして使える、モジュール化された汎用関数を公開する。
単に存在有無を返すだけでなく、リンク切れや予期せぬ例外に対するガードも組み込んだ、実戦仕様のコードだ。

Option Compare Database
Option Explicit

‘ =================================================================================
‘ 模块名: basDatabaseUtility
‘ 概要 : データベースオブジェクトの存在確認および安全性確保に関するユーティリティ
‘ =================================================================================

/

  • 指定されたテーブルがデータベース内に存在するかを高速に判定する
  • @param ByVal strTableName As String – 存在を確認したいテーブル名
  • @return Boolean – 存在する場合は True、存在しない場合は False
  • @remarks Application.CurrentData.AllTables を使用し、エラー発生を伴わない軽量な判定を行う

/
Public Function ExistsTable(ByVal strTableName As String) As Boolean
‘ 不正な引数(空文字など)の早期リターン(ガード cláusula)
If Trim(strTableNamevbNullString) = vbNullString Then
ExistsTable = False
Exit Function
End If

Dim objTable As AccessObject
Dim bResult As Boolean
bResult = False

‘ On Error GoTo を使わない、モダンでクリーンなコレクション探索
On Error GoTo ErrorHandler

For Each objTable In Application.CurrentData.AllTables
If StrComp(objTable.Name, strTableName, vbTextCompare) = 0 Then
bResult = True
Exit For
End If
Next objTable

ExistsTable = bResult
Exit Function

ErrorHandler:
‘ 予期せぬ環境要因によるエラーはログに落とし、安全側に倒してFalseを返す
Debug.Print “[Error] ExistsTable: ” & Err.Description
ExistsTable = False
End Function

実務での活用シナリオ:動的インポート・エクスポート処理

この `ExistsTable` 関数が真価を発揮するのは、外部からのデータインポートや、一時テーブル(TempTable)を動的に生成・破棄するバッチ処理の現場だ。

以下のコードを見てほしい。存在しないテーブルをいきなりクエリやDAOで叩くのではなく、「処理の分岐をあらかじめコントロールする」ことで、メンテナンス性が劇的に向上する。

/

  • 外部CSVのインポート処理(堅牢性重視モデル)

/
Public Sub ExecuteDataImportBatch()
Const TARGET_TABLE As String = “W_Temp_ImportData”

‘ 1. 一時テーブルが存在しない場合は、動的に作成する
If Not ExistsTable(TARGET_TABLE) Then
Call CreateTempImportTable(TARGET_TABLE)
Else
‘ 存在する場合は、前回のゴミデータをクリアするため一度全削除するか、再構築する
CurrentDb.Execute “DELETE FROM ” & QUOTENAME(TARGET_TABLE), dbFailOnError
End If

‘ 2. インポート処理本体へ進む
‘ DoCmd.TransferText … などの処理
MsgBox “インポートの準備が完了しました。”, vbInformation, “システム通知”
End Sub

/

  • テーブル動的生成のヘルパー

/
Private Sub CreateTempImportTable(ByVal strTableName As String)
Dim strSQL As String

‘ DDLを使用して安全にテーブルを定義
strSQL = “CREATE TABLE ” & strTableName & ” (” & _
“ID COUNTER CONSTRAINT PrimaryKey PRIMARY KEY, ” & _
“ImportDate DATETIME, ” & _
“DataValue TEXT(255)” & _
“);”

CurrentDb.Execute strSQL, dbFailOnError
End Sub

/

  • 識別子のクォート処理(SQLインジェクションや予約語対策の基本)

/
Private Function QUOTENAME(ByVal strName As String) As String
QUOTENAME = “[” & Replace(strName, “]”, “]]”) & “]”
End Function

チーフアーキテクトからの提言

AccessVBAの開発現場では、「動けばいいや」という場当たり的なコードが技術的負債として積み重なり、のちにシステム全体の崩壊を招くケースを嫌というほど見てきた。

今回紹介した `Application.CurrentData.AllTables` を活用した存在チェックは、コードの行数こそわずかだが、「エラーを発生させずに予期せぬ状態をハンドリングする」というプロフェッショナルな設計思想そのものだ。

無駄なエラーハンドリングを排除し、メタデータをスマートに読み解く。このアプリケーション構築アプローチを取り入れるだけで、君の書くAccess VBAのコードベースは見違えるほど堅牢で、保守性の高い「プロダクト」へと進化するはずだ。

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