こんにちは!Access VBAの世界へようこそ。
ここまで足を踏み入れたということは、あなたも「ただ動くだけのコード」から、「システムの本質を理解したエンジニア」への階段を登り始めている証拠です。
今回は、Accessの裏側を支配する「システムテーブル(隠しテーブル)」の安全な操作方法についてお話しします。
「システムテーブル? なんか触っちゃいけない怖い領域のやつでしょ?」
その直感は大正解です。ここを不用意にいじると、Accessデータベースが一瞬で起動しなくなるという悲劇(ロストテクノロジー化)が起きます。
でも、安心してください。これからお伝えする「鉄則」と「安全なリードオンリー(読み取り専用)の技」さえマスターすれば、実務で役立つ強力な武器になります。
ここをクリアすれば、あなたのAccess VBAのスキルは一段と深まりますよ。一緒に本質を学んでいきましょう!
—
1. そもそも「システムテーブル」とは何か?
Accessの画面(ナビゲーションウィンドウ)を何気なく見ていて、`MSysObjects` や `MSysAccessObjects` なんていう名前のテーブルを見たことはありませんか?(普段は隠されていて見えない設定になっていますが)
これらはAccess自身がデータベースの構造を管理するために使っている超重要テーブルです。
- 何が入っているのか?
- データベース内にあるすべてのテーブル、クエリ、フォーム、レポート、マクロの名前や作成日時、IDなどの「メタデータ(データについてのデータ)」がすべてつまっています。
例えるなら、ここは人間でいう「脳みそや神経系」です。
ここに直接メスを入れて「あ、間違えて血管を切っちゃった」なんてことになったら、データベースは即死します。だからこそ、原則としてシステムテーブルの直接書き換え(追加・更新・削除)は厳禁なのです。
—
2. だけど、なぜVBAで触る必要があるのか?(実務での活用例)
「危ないなら触らなきゃいいじゃないですか」と思いますよね。
しかし、実務の現場では、システムテーブルの情報を「安全に読み取る」ことで、非常にスマートな自動化が可能になります。
【実務での活用例】
- 「特定のテーブルやクエリが本当に存在するか」をVBAで動的にチェックしたいとき
- データベース内にある全テーブルのレコード数を一括で監査(レポート)したいとき
- 古いバックアップテーブルや、ユーザーが作り散らかしたゴミクエリを安全に検知したいとき
Accessには、こうしたシステム情報を安全に引き出すための公式なルート(DAOの`TableDefs`や`Container`オブジェクト)が用意されています。今回は、その中でも最も安全かつ実用的なアプローチをコードで解説します。
—
3. 【実践】システムテーブルに頼らずとも安全に情報を取得するVBA
実は、先ほど名前を出した `MSysObjects` を直接SQLで叩かなくても、Accessの標準機能(DAO)を使えば、安全にシステム内部の情報を覗き見ることができます。
以下のコードは、「データベース内にあるすべてのユーザーテーブルの名前とレコード数を、イミディエイトウィンドウに安全に出力する」プログラムです。
Sub CheckAllTablesSafely()
‘ 宣言:DAOのデータベースとテーブル定義オブジェクト
Dim db As DAO.Database
Dim tdf As DAO.TableDef
Dim lngRecordCount As Long
On Error GoTo ErrorHandler
‘ 現在のデータベースへの参照を取得
Set db = CurrentDb
Debug.Print “=== データベース内テーブル監査レポート ===”
‘ すべてのテーブル定義をループ処理する
For Each tdf In db.TableDefs
‘ 【重要】テーブル名の先頭が “MSys” または “~” で始まるものは
‘ システムテーブルや一時テーブルなので、処理対象から華麗にスルーする!
If Left(tdf.Name, 4) <> “MSys” And Left(tdf.Name, 1) <> “~” Then
‘ レコード数を安全に取得(※リンクテーブル等の例外対策も兼ねる)
On Error Resume Next
lngRecordCount = db.TableDefs(tdf.Name).RecordCount
If Err.Number <> 0 Then
lngRecordCount = -1 ‘ 取得できない場合は-1とする
Err.Clear
End If
On Error GoTo ErrorHandler ‘ エラー監視を元に戻す
‘ 結果を出力
If lngRecordCount >= 0 Then
Debug.Print “テーブル名: ” & tdf.Name & ” (レコード数: ” & Format(lngRecordCount, “#,
0″) & “件)”
Else
Debug.Print “テーブル名: ” & tdf.Name & ” (外部接続・レコード数不明)”
End If
End If
Next tdf
Debug.Print “========================================”
MsgBox “テーブルの監査が完了しました。イミディエイトウィンドウを確認してください。”, vbInformation, “完了”
Exit_Routine:
‘ メモリの解放(プログラマの美学)
Set tdf = Nothing
Set db = Nothing
Exit Sub
ErrorHandler:
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical, “エラー”
Resume Exit_Routine
End Sub
コードの解説と「プロの知見」
1. `Left(tdf.Name, 4) <> “MSys”` による自己防衛
ここが今回のテーマのキモです。システムテーブルに誤ってアクセスしたり、書き込みエラーを起こさないために、最初から「MSys」で始まる名前は完全に無視(フィルター)しています。このフィルターを挟むだけで、安全性は劇的に跳ね上がります。
2. 一時テーブル(`~`で始まるもの)の除外
Accessが内部的に一時作成するクエリのキャッシュなども除外するため、`~`(チルダ)のチェックも入れています。実務でありがちな「なぜか見えないゴミ」に怯える必要がなくなります。
3. `On Error Resume Next` による堅牢性
巨大なリンクテーブル(SQL Serverや別ファイルへの接続)のレコード数を直接カウントしようとすると、ネットワークの遅延や権限エラーでVBAがクラッシュすることがあります。あえてエラーを一時的に無視し、取得できない場合は `-1` を返すことで、マクロ全体の耐性を高めています。
—
4. 陥りやすい罠とやってはいけないNG行為
ここで、初心者がやってしまいがちな「危険な罠」をいくつかご紹介します。反面教師として頭の片隅に入れておいてください。
- 罠1:`MSysObjects` に対して `CurrentDb.Execute “DELETE FROM MSysObjects…”` を実行する
- 結果: 即死(データベースの破損)。Accessが二度と開かなくなります。バックアップがない場合、数日分の開発作業が水の泡になります。
- 罠2:ナビゲーションウィンドウで「隠しオブジェクトの表示」にチェックを入れ、うっかりシステムテーブルをダブルクリックして値を書き換える
- 結果: リレーションシップやフォームの紐付けが狂い、プログラムがあちこちでエラーを吐き始めます。「見えても触るな、神聖領域」が鉄則です。
どうしても `MSysObjects` をクエリやSQLで参照したい場合は、「必ずSELECT文(読み取り)だけに留めること」。更新・削除クエリ(`UPDATE`, `DELETE`, `INSERT`)をシステムテーブルに対して発行することは、絶対に避けてください。
—
まとめ:安全なコードでAccessの主人となろう
今回は、隠しテーブルやシステムテーブルを安全に扱うための極意についてお伝えしました。
- システムテーブルはAccessの脳みそ。直接の書き換え・削除は絶対NG!
- DAOの `TableDefs` を使い、`MSys` や `~` を除外して安全に読み取る。
- 実務では「監査」や「存在チェック」の目的に絞ってスマートに活用する。
ここをクリアしたあなたは、もうただのビギナーではありません。裏側の仕組みまで見通せる、ワンランク上のAccess VBAエンジニアです。
ぜひ、日々の業務自動化にこの安全な知見を取り入れて、堅牢で美しいシステムを作り上げていってくださいね。あなたの開発ライフを応援しています!
