こんにちは!Access VBAの奥深い世界へようこそ。
マクロの記録ボタンを押すだけの世界から一歩抜け出し、自分の手でデータベースを自在に操りたい――そんな熱意を持つあなたへ、今日はとびきりエキサイティングなテーマをお届けします。
テーマはずばり、【プロ】テーブル定義の「完全同期」を実現する差分抽出アルゴリズムの極意です。
「本番環境と開発環境で、いつの間にかテーブルの構造が変わってしまい、エラーが出る……」
「フィールドを追加しただけなのに、わざわざテーブルを作り直すのは面倒だし怖い……」
現場でこんな絶望を味わったことはありませんか?
大丈夫。ここをクリアすれば、あなたも単なる「VBAの利用者」から、システムを意のままに構築する「アーキテクト」への階段を確実に登ることができます。優しく、深く、一緒に紐解いていきましょう!
—
1. なぜ「テーブル定義の同期」がプロの腕の見せ所なのか?
Accessでシステムを運用していると、改修のたびに「テーブルの設計変更」が発生します。
「フィールドを追加したい」「データ型を変えたい」「インデックスを貼りたい」……。
素朴なアプローチとしては、「古いテーブルを削除して、新しいテーブルを丸ごとインポートし直す」という方法が思い浮かぶかもしれません。しかし、これはプロの現場ではタブーです。なぜなら、既存のデータが吹き飛ぶリスクがありますし、何より巨大なデータを扱う際にパフォーマンスが絶望的に落ちるからです。
真にエレガントな解決策――それは、「2つのデータベースを比較し、変わった部分(差分)だけを見つけ出して、最小限の命令(DDL)でアップデートする」こと。これが今回解説する「完全同期アルゴリズム」です。
—
2. 同期アルゴリズムの全体像:3つのステップ
テーブル定義を同期するとは、要するに「間違い探し」です。
比較元のデータベース(マスター)と、比較先のデータベース(ターゲット)を突き合わせ、以下の3つを特定します。
1. 追加すべきもの:マスターにはあるが、ターゲットにないフィールドやインデックス
2. 削除すべきもの:ターゲットにはあるが、マスターには不要なフィールドやインデックス
3. 変更すべきもの:名前は同じだが、データ型やサイズが違うフィールド
これらをVBAのDAO(Data Access Objects)を使ってスマートに検出していきます。
「ここをクリアすれば、Access VBAの基本はバッチリですよ!」と胸を張れるよう、実際のコードを見ていきましょう。
—
3. 実装コード:差分抽出と自動DDL実行エンジン
以下のコードは、外部のマスターデータベースからテーブル定義を読み込み、現在のデータベースのテーブルと比較して、足りないフィールドを自動で追加する実用的なプロシージャです。
Option Compare Database
Option Explicit
‘ =========================================================================
‘ プロシージャ名 : SyncTableDefinition
‘ 概要 : マスターDBからテーブル定義を読み込み、自DBの同名テーブルに不足フィールドを追加する
‘ =========================================================================
Public Sub SyncTableDefinition(ByVal masterDbPath As String, ByVal targetTableName As String)
Dim dbMaster As DAO.Database
Dim dbCurrent As DAO.Database
Dim tdfMaster As DAO.TableDef
Dim tdfCurrent As DAO.TableDef
Dim fldMaster As DAO.Field
Dim fldExists As Boolean
Dim strSQL As String
On Error GoTo ErrorHandler
‘ 1. マスターDBを外部参照として開く
Set dbMaster = OpenDatabase(masterDbPath, True) ‘ 読み取り専用
Set dbCurrent = CurrentDb
‘ 2. 双方のTableDefオブジェクトを取得
‘ ※存在チェックの例外処理は省略していますが、実務ではIF文等で存在確認を入れます
Set tdfMaster = dbMaster.TableDefs(targetTableName)
Set tdfCurrent = dbCurrent.TableDefs(targetTableName)
‘ 3. マスター側のフィールドを基準に、ターゲット側と比較
For Each fldMaster In tdfMaster.Fields
fldExists = False
‘ ターゲット側に同じ名前のフィールドがあるか走査
Dim fldCurrent As DAO.Field
For Each fldCurrent In tdfCurrent.Fields
If LCase(fldCurrent.Name) = LCase(fldMaster.Name) then
fldExists = True
Exit For
End If
Next fldCurrent
‘ 4. フィールドが存在しない場合、ALTER TABLE文(DDL)を動的生成して追加
If Not fldExists Then
strSQL = “ALTER TABLE [” & targetTableName & “] ADD COLUMN [” & fldMaster.Name & “] ” & GetDataTypeString(fldMaster) & “;”
‘ DDLの実行
dbCurrent.Execute strSQL, dbFailOnError
Debug.Print “【追加成功】フィールド: ” & fldMaster.Name & ” を追加しました。”
End If
Next fldMaster
MsgBox “テーブル [” & targetTableName & “] の構造同期が完了しました!”, vbInformation, “同期完了”
CleanUp:
‘ オブジェクトの解放(メモリリークを防ぐプロの作法)
If Not dbMaster Is Nothing Then dbMaster.Close
Set dbMaster = Nothing
Set dbCurrent = Nothing
Exit Sub
ErrorHandler:
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical, “同期エラー”
Resume CleanUp
End Sub
‘ =========================================================================
‘ 補助関数 : DAOのデータ型数値から、DDL用のデータ型文字列に変換する
‘ =========================================================================
Private Function GetDataTypeString(fld As DAO.Field) As String
Select Case fld.Type
Case dbLong: GetDataTypeString = “LONG”
Case dbText: GetDataTypeString = “TEXT(” & fld.Size & “)”
Case dbMemo: GetDataTypeString = “MEMO”
Case dbDate: GetDataTypeString = “DATETIME”
Case dbBoolean: GetDataTypeString = “YESNO”
Case dbCurrency: GetDataTypeString = “CURRENCY”
Case dbDouble: GetDataTypeString = “DOUBLE”
Case dbInteger: GetDataTypeString = “INTEGER”
Case Else: GetDataTypeString = “TEXT(255)” ‘ フォールバック
End Select
End Function
—
4. コードの深掘り:プロが仕込んだ「3つのこだわり」
上記のコードには、単なる「動くコード」を超えた、プロのエンジニアとしてのこだわりが散りばめられています。
① 大文字・小文字を区別しない比較 (`LCase`)
データベースの世界では、`CustomerID` も `customerid` も同じ意味で扱われることがあります。人間はうっかり大文字小文字を間違える生き物なので、比較する際は必ず `LCase` で小文字に統一して判定するのが鉄則です。
② DDL(Data Definition Language)の活用
`CurrentDb.Execute strSQL, dbFailOnError` の部分です。レコードを追加・更新する `INSERT` や `UPDATE` ではなく、テーブルそのものの構造を変える `ALTER TABLE` というSQL命令を使っています。これにより、Accessの画面を開くことなく、裏側で一瞬にして構造をアップデートできます。
③ 徹底的なオブジェクトの解放 (`CleanUp`)
VBAで外部データベースやDAOオブジェクトを扱うとき、最も恐ろしいのはメモリリーク(メモリの解放漏れ)です。これを放置すると、Accessが徐々に重くなり、最終的にフリーズします。プロは必ず `CleanUp` ラベルを用意し、エラーが起なかろうが起きようが、確実に `Close` と `Set = Nothing` を行います。
—
5. 陥りやすい罠とエラー回避の知見
このレベルの自動化に挑むと、必ず次のような壁にぶつかります。あらかじめ知っておけば怖くありません。
- 「排他制御(Exclusive)」の罠
外部データベースが開かれているとき、他のユーザーが排他モードで開いていると `OpenDatabase` でエラーになります。共有モード (`True`) で開く、あるいは自分以外の接続がないことを確認する配慮が必要です。
- データ型のマッピングの限界
AccessのDAOが持つデータ型(`dbLong` や `dbText` など)は多岐に渡ります。今回は主要な型に絞って `GetDataTypeString` 関数で変換していますが、長さを伴うテキストや、長整数(オートナンバー)の扱いは少し複雑です。まずは基本の型からマスターしていきましょう。
—
おわりに:エンジニアとしての自信を手に入れよう
お疲れ様でした!今回は「テーブル定義の完全同期」という、一歩進んだ高度なVBA制御の世界を覗いてみました。
最初は難しく感じたかもしれませんが、やっていることは「2つのリストを見比べて、足りないものを足しているだけ」です。これをコードで自動化できたとき、あなたのAccess開発スキルは間違いなく一段上のステージに到達しています。
「ここをクリアすれば、Access VBAの基本はバッチリですよ!」
この知見を武器に、ぜひご自身の業務自動化システムをより堅牢でスマートにアップデートしてみてください。あなたの開発ライフが、さらに快適でクリエイティブなものになることを応援しています!
