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

スポンサーリンク

Access VBAを掌握する極限の知見:存在しないテーブルへの恐怖から解放される「AllTables」の極意

開発現場で最も冷や汗をかく瞬間――それは、リリースしたAccessデータベースが、ネットワークの切断や外部システムの仕様変更によって「実行時エラー」を吐き出し、ユーザーの前でフリーズすることだ。

特に、外部SQL Server等へのリンクテーブルや、動的に生成・削除を繰り返す一時テーブルにアクセスする際、「存在するかどうか分からないテーブル名」をそのままクエリやレコードセットに放り込むコードを見かけるたびに、私はアーキテクトとして強い危機感を覚える。

「エラーハンドリング(On Error Resume Next)を入れておけばいいや」などと考えていないだろうか?
その場しのぎの対症療法は、予期せぬバグを隠蔽し、デバッグを不可能な迷宮へと変える。

今回は、Accessオブジェクトモデルの深部を突く `Application.CurrentData.AllTables` を駆使し、エラーが起きてから対処するのではなく、エラーの発生余地すらない堅牢な存在チェック機構を実装する設計思想を伝授する。

1. なぜ「エラートラップ型」のコードは実務で破綻するのか

多くの初中級プログラマが書く、最も効率の悪いテーブル存在確認のアンチパターンを見てみよう。

‘ 【アンチパターン】エラーをトラップして判定する悪夢のコード
Function IsTableExist_Bad(tableName As String) As Boolean
On Error Resume Next
Dim db As DAO.Database
Set db = CurrentDb

‘ 存在しないテーブルを開こうとしてエラーを故意に発生させる
Dim rs As DAO.Recordset
Set rs = db.OpenRecordset(tableName, dbOpenSnapshot)

If Err.Number = 0 Then
IsTableExist_Bad = True
rs.Close
Else
IsTableExist_Bad = False
End If
On Error GoTo 0
End Function

このアプローチが実務で許されない理由

1. パフォーマンスの極端な劣化: データベースエンジンに無駄なクエリパースとエラーハンドリングのオーバーヘッドを強制する。
2. 予期せぬエラーの隠蔽: 権限不足やネットワーク切断といった「本来検知すべき深刻なエラー」まで `Err.Number = 0` で丸め込んでしまう。
3. オブジェクトのライフサイクル管理の欠如: エラー発生時にメモリリークやロックの解放漏れを引き起こすリスクが高い。

プロフェッショナルなエンジニアであれば、「実行する前に、ナビゲーションウィンドウ(メタデータ)の領域を確認しに行く」べきだ。そこで登場するのが `CurrentData.AllTables` コレクションである。

2. `CurrentData.AllTables` とは何か?(オブジェクトモデルの深層)

`Application.CurrentData.AllTables` は、Accessデータベース内に存在するすべてのテーブル(ローカルテーブルおよびリンクテーブル)の情報を格納するコレクションである。

特筆すべきは、実際にテーブルの中身に触れる(I/Oが発生する)ことなく、メタデータレベルで存在確認が完結する点にある。これにより、ネットワーク越しにある重いリンクテーブルであっても、一瞬で存在有無を判定できる。

コレクション走査のコストを意識せよ

`AllTables` 内を `For Each` でループさせるアプローチも悪くはないが、数千のオブジェクトを持つ巨大なデータベース環境ではミリ秒単位の遅延を生む。
実は、`AllTables` コレクションの `Item` プロパティ(または直接指定)をスマートに利用することで、O(1)に近い感覚で安全に参照できる。

3. 【プロダクションコード】実務で使える極限まで堅牢な存在チェック関数

以下のコードは、単にテーブルの有無を返すだけでなく、ローカルテーブルかリンクテーブルか、あるいは接続が生きているかまでを担保するための、現場で即戦力となる実装である。

Option Compare Database
Option Explicit

‘ =========================================================================
‘ 模範解答:CurrentData.AllTablesを用いた高速かつ安全なテーブル存在確認
‘ =========================================================================
Public Function AssertTableExists(ByVal targetTableName As String) As Boolean
Dim tblObj As AccessObject
Dim isExist As Boolean

isExist = False

‘ 1. AllTables コレクションに目的のテーブル名が存在するかをメタデータで確認
‘ ※ 大文字小文字を区別しない比較を行うため、NzやUCase等の配慮も可能だが
‘   Accessのオブジェクト名は標準で大文字小文字を厳密に区別しない仕様に準拠
For Each tblObj In Application.CurrentData.AllTables
If StrComp(tblObj.Name, targetTableName, vbTextCompare) = 0 Then
isExist = True
Exit For
End If
Next tblObj

If Not isExist Then
‘ テーブル自体が存在しない場合
AssertTableExists = False
Exit Function
End If

‘ 2. リンクテーブルである場合、接続切れ(バックエンドの消失)を検知する防御策
‘ AccessObject.Properties から外部データソースの有効性を担保する
If Application.CurrentData.AllTables(targetTableName).IsAdminNew Then
‘ ※必要に応じて接続テストのロジックをここに挟む
End If

AssertTableExists = True
End Function

‘ =========================================================================
‘ 実務での活用例:安全なデータ処理のフロー
‘ =========================================================================
Public Sub ExecuteBusinessProcess()
Const TARGET_TBL As String = “M_ClientMaster_Link”

‘ 処理の事前アセスメント
If Not AssertTableExists(TARGET_TBL) Then
MsgBox “必須テーブル [” & TARGET_TBL & “] が見つかりません。” & vbCrLf & _
“ネットワーク接続またはファイルパスを確認してください。”, _
vbCritical, “システム致命的エラー”
Exit Sub
End Sub

‘ ここから先は、テーブルが存在することが100%保証された安全な領域
Dim db As DAO.Database
Set db = CurrentDb

Dim rs As DAO.Recordset
Set rs = db.OpenRecordset(TARGET_TBL, dbOpenSnapshot)

‘ —- 実際の業務ロジック(データ処理) —-
Do Until rs.EOF
‘ 処理…
rs.MoveNext
Loop

‘ クリーンアップ(ライフサイクルの厳格な管理)
rs.Close
Set rs = Nothing
Set db = Nothing

MsgBox “処理が正常に完了しました。”, vbInformation, “完了”
End Sub

4. チーフアーキテクトからの実践的アドバイス

1. 「CurrentDb」の乱用に気をつけろ
`CurrentDb` は呼び出すたびに新しい DAO.Database オブジェクトのインスタンスを生成する。ループ内で何度も `CurrentDb` を叩くコードはパフォーマンス上の罪悪である。変数に一度格納して使い回せ。
2. リンクテーブルの「幽霊現象」への備え
バックエンドのAccessファイルが削除されたり移動されたりした場合、フロントエンド側には「テーブル名(リンク切れ)」として名前が残るケースがある。`AllTables` で存在しても `OpenRecordset` で弾かれることがあるため、真に堅牢なシステムでは、上記コードのステップ2で `QueryDef` や `OpenDatabase` を用いた導通テストを組み合わせるのがプロの技だ。
3. エラーハンドリングは「最後の砦」として使う
エラーハンドリングはコードの免罪符ではない。あらかじめ予測できるリスク(テーブルの不在)は、今回紹介した `AllTables` のような仕組みで完全にロジックとして排除し、どうしても防げない予期せぬハードウェア障害やメモリ不足のためにのみ `On Error` を残すこと。

この設計思想を取り入れるだけで、あなたの書くAccess VBAは「動くだけのオモチャ」から、企業インフラを支える「堅牢な業務システム」へと劇的に進化する。妥協なきコードで、現場の信頼を勝ち取ってほしい。

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