【Access VBA】脱・グローバル変数!エラーでも値が消えない「TempVars」の極意
Access VBAでシステムを開発・保守していると、ログインユーザーのIDやシステムの設定値など、アプリケーション全体で使い回したいデータが出てきます。
従来のVBA開発では、標準モジュールで Public 宣言した「グローバル変数」を使うのが一般的でした。しかし、これには**「実行時エラーが起きてコードが停止(リセット)されると、メモリ上の変数がすべて初期化されてしまう」**という致命的な弱点があります。
稼働中にこの「突然の変数初期化」が起きると、誰がレコードを更新したか分からないといった深刻なデータ不整合を引き起こしかねません。
そこで今回は、Access 2007以降で標準搭載されている強力な状態管理機能
**「TempVars(一時変数)コレクション」**について、その裏側の仕組みや限界、そして過去の手法との比較まで踏み込んで解説します。
1. なぜ「変更初期化」を防げるのか?(TempVarsの仕組み)
結論から言うと、TempVarsは**「VBAエンジン」ではなく「Access本体」がメモリを管理している**ためです。
- 通常のグローバル変数:
- VBAの実行環境(VBE)がメモリを持っています。未処理のエラーで処理が停止したり、開発者がエディタで「リセット(■ボタン)」を押したりすると、VBEのメモリが解放されて中身が消えます。
- TempVars:
- Accessアプリケーション本体(
MSACCESS.EXE)の機能として実装されています。VBAから見ると「外部のAccess本体に値を預けている」状態です。 - そのため、VBAの実行コンテキストがリセットされても、Access本体が起動している限り値はそのまま保持され続けます。
- Accessアプリケーション本体(
2. TempVarsを使う3つの強力なメリット
① クエリ(SQL)やマクロから直接参照できる
グローバル変数をクエリの抽出条件(WHERE句)で使いたい場合、わざわざ値を返すためだけの関数(Getter)を作る必要がありました。
TempVarsなら、クエリビルダの抽出条件やSQLビューの中に、直接以下のように書くことができます。
-- クエリでの使用例 SELECT * FROM T_売上 WHERE 担当者CD = [TempVars]![現在の担当者]
これにより、無駄なVBAコードが減り、設計が非常にすっきりします。
② コレクションとして直感的に管理できる
「キーと値」のペアで追加していくスタイルなので、未ログイン(変数が空)の判定や、ログアウト時のデータの一括クリアなどが簡単です。
③ For Each でループ処理(デバッグ)が可能
TempVarsはコレクションオブジェクトなので、VBAの For Each を使って中身を簡単に列挙できます。現在のセッション情報を一覧表示したい時に非常に便利です。
Sub CheckTempVars()
Dim tv As TempVar
For Each tv In TempVars
Debug.Print "変数名: " & tv.Name & " / 値: " & tv.Value
Next tv
End Sub
3. 基本的な使い方
使い方は非常にシンプルで、ディクショナリ(連想配列)のように扱えます。
' 1. 値の格納(追加・更新)※既存のキーがあれば上書きされます
TempVars.Add "現在の担当者", "EMP001"
' 2. 値の取得
Dim currentUserID As String
currentUserID = TempVars("現在の担当者").Value
' 3. 値の存在チェック(未ログイン判定などに)
If IsNull(TempVars("現在の担当者")) Then
MsgBox "ログイン情報がありません。再度ログインしてください。"
End If
' 4. 特定の変数を削除
TempVars.Remove "現在の担当者"
' 5. すべての変数をクリア(ログアウト処理などに最適)
TempVars.RemoveAll
4. 【重要】TempVarsの3つの限界と落とし穴
非常に便利なTempVarsですが、万能ではありません。実務で使う上で絶対に知っておくべき制限があります。
限界1:文字数の上限は「約65,535文字(64KB)」
通常のVBAの String 変数は約20億文字(2GB)まで格納できますが、TempVarsは昔のメモ型フィールドと同じ約65,535文字の壁が存在します。これを超える文字列を代入しようとすると実行時エラーになります。 ログインIDや、SQLのIN句に渡す数千文字のカンマ区切りリスト程度なら問題ありませんが、テキストファイルの中身を丸ごと読み込んだり、画像をBase64化した巨大なデータを格納したりしてはいけません。
限界2:オブジェクト型は格納できない
格納できるのは文字列(String)や数値(Integer, Longなど)、日付(Date)、ブール値(Boolean)といった基本データ型のみです。Recordset や Form などのオブジェクトを格納しようとするとエラーになります。
限界3:重いループ処理でのパフォーマンス低下
TempVarsは「VBA ⇔ Access本体」という境界を越えてやり取りするため、通常の変数よりわずかにアクセスが遅いです。 通常の使用(画面遷移やクエリの条件)では体感差はゼロですが、For i = 1 To 1000000 のような数万回の重いループ処理の中で毎回TempVarsを読み書きすると、明確に処理が遅くなります。ループ内で使う場合は、一度VBAのローカル変数に代入してから使いましょう。
(補足)Access自体の強制終了には無力
「VBAのリセット」には耐えられますが、タスクマネージャーからのキルや、MSACCESS.EXE 自体がクラッシュした場合は、メモリ上のデータなので当然消滅します。
5. コラム:昔のプログラマーはどうしていたか?(代替手段)
TempVarsがなかったAccess 2003以前の時代や、要件によっては、以下のような手法で「突然の変数初期化」と戦っていました。
| 手法 | 保存場所 | 特徴と使い所 |
| 隠しフォーム | Access UIのメモリ | 起動時に非表示のフォームを開きっぱなしにして、テキストボックスに値を保持する伝統的手法。画面を「表示」に切り替えれば現在の値を視覚的にデバッグできるメリットがありました。 |
| ローカルテーブル | ディスク (DB内) | 1行だけのテーブルに物理的に書き込む手法。Access本体が強制終了しても値が残る究極の堅牢性を持ちます。65,535文字を超える巨大テキストを安全に保持したい場合は現在でもこの手法が正解です。 |
| レジストリ | OS領域 | SaveSetting 関数を使いOS側に保存。PCを再起動してAccessを開き直しても値が残るため「前回のログインIDを記憶する」機能などに使われます。 |
まとめ
Access VBAにおける状態管理は、グローバル変数からの脱却が安定稼働への第一歩です。
TempVars を活用しつつ、文字数制限などの「限界」を正しく理解することで、予期せぬエラーに強い堅牢なシステムを構築することができます。既存システムのリファクタリングや新規開発の際は、ぜひ積極的に採用してみてください!
大手SIerに長年常駐し大規模システムの経験を重ねプログラムスキルとDB設計を磨く。AccessおよびExcelのVBAを得意とする。
⇒お仕事のご依頼はこちら


