【実務・中級編】【初心者】テーブルのプロパティから「定型入力」をVBAで一括設定し、電話番号や郵便番号の入力を統一する – Access VBA解析バイブル

スポンサーリンク

【Access VBA極限活用】定型入力の一括制御でデータ品質を死守せよ!TableDefを操るテーブル設計の自動化

開発現場でこんな絶望を味わったことはないか?

「ユーザーが電話番号を『03-1234-5678』と入れたり、『0312345678』と入れたり、果ては全角で入力したりして、集計クエリが使い物にならない」
「後から全テーブルの郵便番号フィールドにハイフン付きの定型入力を強制しろと言われたが、手作業で何十個もデザインビューを開いてポチポチ設定するのは苦行でしかない」

断言しよう。手作業でのテーブル定義の変更は、百害あって一利なしだ。人間がやる以上、設定漏れやミスが必ず起きる。そして何より、DBのスキーマ変更は「コード(VBA)」で管理してこそ、真のモダンな開発と言える。

今回は、Access VBAの心臓部である `TableDef` オブジェクトを完全掌握し、指定したテーブル群の「定型入力(InputMask)」を一瞬で、かつ完全に統一するプロダクションコードを伝授する。

—

なぜ「定型入力」の統一が業務システムに絶対不可欠なのか?

UI層(フォーム)だけで入力制御をしている甘いシステムを見かけるが、それはプログラミングの敗北だ。フォームを経由せずに直接テーブルを開いてデータを改変されたり、外部からインポートされたりした瞬間、データはゴミの山と化す。

テーブルの物理層(Fieldオブジェクト)において、`InputMask` プロパティを厳格に定義することのメリットは以下の通りだ。

1. データ整合性の担保: 半角・全角の揺れ、ハイフン抜けを物理的にシャットアウトする。
2. 保守性の爆発的向上: 変更が必要になった際も、VBAのスクリプトを1箇所修正して走らせるだけで、全テーブルが瞬時にアップデートされる。
3. 属人性の排除: 「誰が作ったか分からない」ブラックボックスなデータベースを撲滅できる。

—

【アーキテクト直伝】TableDef操作における3つの鉄則

コードを書く前に、Access VBAでデータベース構造をいじる際の「地雷」を踏まないための知見を共有しよう。

1. 排他制御(Exclusive)とトランザクションの意識

`TableDef` や `Field` のプロパティを変更する操作は、データベースのスキーマ(構造)を書き換える。当然、他のユーザーがそのテーブルを開いている状態で実行すると、ロック競合エラー(エラー 3048 や 3216 など)を引き起こす。
実務では、必ず対象のデータベースを排他制御モードで開くか、実行前にコネクションの競合ハンドリングを入れるべきだ。

2. プロパティの「遅延作成」トラップ

Accessのテーブルやフィールドにおいて、`InputMask` などの拡張プロパティは、初期状態では存在しない(隠しプロパティ扱い)ケースがある。
存在しないプロパティにいきなり値を代入しようとすると、冷徹に「実行時エラー 3270: プロパティが見つかりません」が突きつけられる。
したがって、「プロパティが存在するか確認し、なければ新規作成して追加する」という防御的コード(Defensive Code)が必須となる。

—

コピペで使える!定型入力一括設定モジュール

それでは、実務の現場でそのまま動かせる堅牢なコードを公開しよう。
このプロシージャは、指定したプレフィックス(例: `M_` や `T_`)を持つテーブルを走査し、合致するフィールド名(「電話番号」「郵便番号」など)に対して、自動的に適切な `InputMask` を流し込む。

Option Compare Database
Option Explicit

‘ =========================================================================
‘ 処理名 : BatchUpdateInputMask
‘ 概要 : 指定したデータベース内のテーブル群に対し、特定のフィールドの
‘ 定型入力(InputMask)を一括設定する
‘ 備考 : プロパティが存在しない場合は自動生成する安全設計
‘ =========================================================================
Public Sub BatchUpdateInputMask()
Dim db As DAO.Database
Dim tdf As DAO.TableDef
Dim fld As DAO.Field

Dim targetTablePattern As String
Dim phoneMask As String
Dim zipMask As String

Dim updatedCount As Long

On Error GoTo ErrorHandler

‘ ターゲットとするテーブルのプレフィックスやキーワード(必要に応じて変更)
‘ ここでは「T_」で始まる実テーブルを対象とする(システムテーブルは除外)

‘ 定型化の定義(Accessの標準的なマスク書式)
‘ 0 = 必須数値, L = 必須英字, 9 = 任意数値, & = 任意文字
phoneMask = “000-0000-0000;0;_” ; ‘ 電話番号 (例: 03-1234-5678)
zipMask = “000-0000;0;_” ; ‘ 郵便番号 (例: 100-0001)

Set db = CurrentDb()
updatedCount = 0

‘ データベース内の全テーブルをループ
For Each tdf In db.TableDefs
‘ システムテーブル(MSysで始まる)や一時テーブルを除外
If Left(tdf.Name, 4) <> “MSys” And Left(tdf.Name, 1) <> “~” Then

‘ リンクテーブル(Connectプロパティに文字がある)は除外
If tdf.Connect = “” Then

For Each fld In tdf.Fields
‘ フィールド名に応じた定型入力を動的に判定・設定
Select Case fld.Name
Case “電話番号”, “TEL”, “Tel”, “Phone”
Call SetPropertySafely(fld, “InputMask”, dbText, phoneMask)
updatedCount = updatedCount + 1
Debug.Print “設定完了 [電話番号]: ” & tdf.Name & “.” & fld.Name

Case “郵便番号”, “ZIP”, “Zip”, “PostalCode”
Call SetPropertySafely(fld, “InputMask”, dbText, zipMask)
updatedCount = updatedCount + 1
Debug.Print “設定完了 [郵便番号]: ” & tdf.Name & “.” & fld.Name

‘ 必要に応じて他のフィールドも追加可能
‘ Case “FAX”
‘ Call SetPropertySafely(fld, “InputMask”, dbText, phoneMask)
‘ updatedCount = updatedCount + 1

End Select
Next fld

End If
End If
Next tdf

MsgBox “定型入力の一括設定が正常に完了しました。” & vbCrLf & _
“更新されたフィールド数: ” & updatedCount & ” 件”, vbInformation, “処理成功”

CleanUp:
Set fld = Nothing
Set tdf = Nothing
Set db = Nothing
Exit Sub

ErrorHandler:
MsgBox “予期せぬエラーが発生しました。” & vbCrLf & _
“Error ” & Err.Number & “: ” & Err.Description, vbCritical, “致命的エラー”
Resume CleanUp
End Sub

‘ =========================================================================
‘ 補助プロシージャ : SetPropertySafely
‘ 概要 : DAOオブジェクトのプロパティが存在しない場合に新規作成して値を設定する
‘ =========================================================================
Private Sub SetPropertySafely(obj As Object, propName As String, propType As Integer, propValue As Variant)
On Error GoTo SetPropError

‘ すでにプロパティが存在する場合は直接代入
obj.Properties(propName) = propValue
Exit Sub

SetPropError:
‘ プロパティが存在しない場合(エラー 3270)は新規作成
If Err.Number = 3270 Then
Dim prp As DAO.Property
Set prp = obj.CreateProperty(propName, propType, propValue)
obj.Properties.Append prp
Set prp = Nothing
Resume Next
Else
‘ その他の予期せぬエラーは上位にスロー
Err.Raise Err.Number, “SetPropertySafely”, Err.Description
End If
End Sub

—

コードのキリンテクト解説:なぜこの設計なのか?

このコードには、現場で生き残るための「こだわり」が詰まっている。

1. リンクテーブルの完全除外 (`tdf.Connect = “”`)
バックエンドのAccessファイルやSQL Server等へのリンクテーブル(ODBC含む)に対して構造変更を試みると、容赦なくエラーが起きる。ローカルの物理テーブルにのみ処理を限定することで、外部要因によるクラッシュを防いでいる。
2. `SetPropertySafely` によるエラーハンドリングの隠蔽
前述した「プロパティ未存在問題(Error 3270)」を汎用ヘルパー関数に閉じ込めている。メインのロジック側で毎回 `On Error` を書く必要がなくなり、コードの可読性が劇的に向上する。
3. イミディエイトウインドウへのログ出力 (`Debug.Print`)
「どのテーブルのどのフィールドが書き換わったか」をコンソールに出力することで、実行後の監査(エビデンス確認)を容易にしている。

—

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

データベース開発において、マニュアル作業は「悪」である。
今回紹介したような `TableDef` を用いたメタデータ操作の自動化を身につければ、テーブル構造の変更や品質標準化は一瞬で終わる。

「数が多いから手作業で…」という甘えを捨て、すべてをコードで支配せよ。それこそが、プロのエンジニアが構築する「壊れないシステム」の第一歩だ。

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