【Access VBAを掌握する極限の知見】定型入力のVBA一括制御によるデータ整合性の強制
システム開発の現場において、データ品質の担保は永遠の課題である。特にMicrosoft Accessを用いたデスクトップデータベース群では、UI層での入力制御に依存しすぎた結果、バックエンドのテーブル層で不正なフォーマットのデータが野積みにされるというアンチパターンが後を絶たない。
電話番号、郵便番号、あるいは社内独自の管理コード。これらが自由入力の野良テキストとして放置された瞬間、後続の集計クエリ、Excelエクスポート、そして外部API連携は破綻する。
GUIのマウス操作によるテーブルデザイナでの設定など論外だ。数多のテーブル、数多のフィールドに対し、人手による設定作業などヒューマンエラーの温床でしかない。
今回は、DAO(Data Access Objects)の深部を叩き、テーブル定義(`TableDef`)およびフィールド(`Field`)の`InputMask`プロパティをVBAで完全に掌握し、プログラムによってデータフォーマットの強制力を担保する極限のテクニックを解説する。
—
1. 根源的アーキテクチャ:なぜUIではなく「テーブル層」で制御するのか
多くの初学者は、フォームのテキストボックスに対して「定型入力」や「入力規則」を設定して満足する。しかし、アーキテクトの視点から言えば、フォームは単なるビューに過ぎない。
- ダイレクトクエリやADO/DAOによる外部からのレコード追加
- VBAからのINSERT/UPDATE文の実行
これらを実行した際、フォームの制御は一切バイパスされる。データベースの整合性を守る最後の防壁は、常にJet/ACEデータベースエンジン(テーブル定義そのもの)でなければならない。
フィールドの `InputMask` プロパティをコードで動的に、かつ網羅的に制御することは、エンタープライズ環境における最低限の衛生管理なのだ。
—
2. 実装コード:DAOによる `InputMask` 一括設定エンジン
以下のコードは、指定したテーブル群、あるいはデータベース内の全テーブルを走査し、特定の命名規則を持つフィールド(例: `TelNo`, `ZipCode`)に対して、強制的に適切な定型入力マスクを流し込む実用プロシージャである。
メモリリークを許さないDAOの解放作法、そして存在しないプロパティへアクセスした際に発生するエラーをいなす堅牢な例外処理(Error Handling)を実装している。
Option Compare Database
Option Explicit
‘ =========================================================================
‘ 模範的アーキテクチャ: テーブル定義動的制御モジュール
‘ 著作権フリー・現場即応型チーフアーキテクト実装
‘ =========================================================================
Public Sub ApplyStandardInputMasks()
On Error GoTo ErrorHandler
Dim dbs As DAO.Database
Dim tdf As DAO.TableDef
Dim fld As DAO.Field
Dim prp As DAO.Property
Dim updatedCount As Long
updatedCount = 0
‘ カレントデータベースの参照を取得
Set dbs = CurrentDb
‘ テーブル定義を走査
For Each tdf In dbs.TableDefs
‘ システムテーブル(MSysで始まるもの)や一時テーブルは除外
If Not (tdf.Name Like “MSys” Or tdf.Name Like “~”) Then
For Each fld In tdf.Fields
‘ 特定のフィールド名、またはデータ型・サフィックスに基づきマスクを判定
Select Case True
‘ 1. 郵便番号パターン (例: 7桁の数字 -> 000-0000)
Case fld.Name Like “郵便” Or fld.Name Like “Zip” Or fld.Name Like “Postal”
Call SetInputMaskSafe(fld, “000-0000;0;_”)
updatedCount = updatedCount + 1
‘ 2. 電話番号/FAX番号パターン (例: 市外局番含む -> 00-0000-0000 など)
Case fld.Name Like “電話” Or fld.Name Like “TEL” Or fld.Name Like “Fax”
Call SetInputMaskSafe(fld, “00-0000-0000;0;_”)
updatedCount = updatedCount + 1
‘ 必要に応じてカスタムパターンを追加
End Select
Next fld
End If
Next tdf
MsgBox “定型入力の一括設定が完了しました。” & vbCrLf & _
“更新されたフィールド数: ” & updatedCount, vbInformation, “アーキテクチャ実行完了”
CleanExit:
‘ オブジェクトの明示的解放(メモリリークの根絶)
Set fld = Nothing
Set tdf = Nothing
Set dbs = Nothing
Exit Sub
ErrorHandler:
MsgBox “致命的なエラーが発生しました: ” & Err.Description, vbCritical, “Error ” & Err.Number
Resume CleanExit
End Sub
‘ =========================================================================
‘ 補助ルーチン: InputMaskプロパティの安全な設定と遅延生成
‘ =========================================================================
Private Sub SetInputMaskSafe(ByRef targetField As DAO.Field, ByVal maskValue As String)
Const ERR_PROPERTY_NOT_FOUND As Long = 3270
On Error GoTo SetError
‘ プロパティが既に存在する場合は値を代入
targetField.Properties(“InputMask”) = maskValue
Exit Sub
SetError:
If Err.Number = ERR_PROPERTY_NOT_FOUND Then
‘ InputMaskプロパティが存在しない場合(新規フィールド等)、
‘ DAOでは動的にプロ集パティオブジェクトを作成して追加する必要がある
Dim prpNew As DAO.Property
Set prpNew = targetField.CreateProperty(“InputMask”, dbText, maskValue)
targetField.Properties.Append prpNew
Set prpNew = Nothing
Resume Next
Else
‘ その他の予期せぬエラーは上位へ波及させる
Err.Raise Err.Number, “SetInputMaskSafe”, Err.Description
End If
End Sub
—
3. チーフアーキテクトが解説するコードの急所
このコードが「素人の書いたVBA」と一線を画す所以を、3つの視点から解説する。
① `InputMask` プロパティの動的生成(DAOの特殊仕様への対応)
AccessのDAOにおいて、`TableDef`や`Field`のプロパティ(`Properties`コレクション)は、デフォルトで存在しないものが多数存在する。
もし対象フィールドに一度も定型入力が設定されたことがない場合、`fld.Properties(“InputMask”) = …` を実行した瞬間に 実行時エラー 3270(プロパティが見つかりません) が発生する。
上記の `SetInputMaskSafe` プロシージャでは、エラー 3270 を捕捉した瞬間に `CreateProperty` メソッドを呼び出し、コレクションに `Append` するという高度なDAOのライフサイクル管理を完全に網羅している。
② メモリリークとオブジェクトの残存問題
Access VBAにおける最大の悪習は、`CurrentDb` やオブジェクト変数を解放せず放置することによる内部キャッシュの肥大化とメモリリークである。
ループの最後、およびエラーハンドラの出口(`CleanExit`)において、`Set … = Nothing` を徹底的に記述し、COMコンポーネントの参照カウンタを確実にデクリメントしている。
③ 柔軟なパターンマッチング
`Like` 演算子と論理演算子を組み合わせることで、物理的なフィールド名が開発者ごとに揺らいでいる(例: `Tel`, `TelNo`, `denwa`)レガシーデータベースであっても、ワイルドカードによる柔軟な一括キャッチが可能となっている。
—
4. 運用上の注意点とさらなる高みへ
このスクリプトを適用するにあたり、以下の実務的知見を胸に刻んでおいてほしい。
1. 既存データとのコンフリクト
すでに文字数が足りない不正なデータや、ハイフンなしで格納されている既存レコードが存在するテーブルに対して `InputMask` を強制適用すると、データ編集時にエラーや予期せぬ切り捨てが発生する。必ず事前にクエリ等で既存データのクレンジング(正規化)を行ってから適用すること。
2. トランザクションとバックアップ
DDL(データ定義言語)に近い操作を伴うため、実行前には必ずデータベースファイルのバックアップ(物理コピー)を取得させるアーキテクチャ上の配慮が不可欠である。
UIに頼る開発は今日で終わりにせよ。データベースの血肉であるテーブル定義そのものをコードで完全統制することこそが、真に堅牢なエンタープライズ・アクセスアプリケーションへの唯一の道である。
