Access VBAで「リレーションシップの爆弾」を無力化する:堅牢な整合性チェックの極意
現場のAccess開発で最も恐ろしいのは、何の前触れもなく発生する「実行時エラー 3200(このレコードは関連付けられているため削除できません)」や、整合性ルールによる唐突な更新拒否だ。
多くの初学者はエラーハンドラでその場しのぎをするが、それは「火が出た後に消火器を探す」のと同じこと。本物のアーキテクトは、火が出る前に防火壁を設計する。
今日は、DAO(Data Access Objects)を駆使し、リレーションシップの構築と整合性チェックを「プログラムの制御下」に置くための、プロフェッショナルな設計思想を伝授する。
—
1. なぜ「手動設定」ではいけないのか?
リレーションシップをAccessのGUIで設定している諸君へ。それは「属人化の温床」だ。
開発環境から本番環境へ移行する際、あるいはデータ更新ツールを配布する際、環境間でリレーション設定が微妙にズレていれば、アプリは一瞬でゴミと化す。
「リレーションはコードで定義し、実行時に検証する」。これが、大規模開発における唯一の正解だ。
—
2. 整合性エラーを「予見」する設計
リレーションシップ(`Relation`オブジェクト)をVBAで扱う際、最も注意すべきは「既に整合性が崩れたデータが存在する状態で、整合性制約を強制しようとすること」だ。
以下のコードは、リレーションを安全に構築するための「防衛的実装」の雛形である。
プロダクションコード:セーフ・リレーションシップ構築
Public Sub EnsureRelationship(strName As String, _
strPrimaryTable As String, _
strForeignTable As String, _
strPrimaryField As String, _
strForeignField As String)
Dim db As DAO.Database
Dim rel As DAO.Relation
Dim fld As DAO.Field
Set db = CurrentDb
‘ 既存のリレーションがあれば一旦削除(再構築の柔軟性を持たせる)
On Error Resume Next
db.Relations.Delete strName
On Error GoTo ErrorHandler
‘ Relationオブジェクトの作成
Set rel = db.CreateRelation(strName, strPrimaryTable, strForeignTable)
rel.Attributes = dbRelationUpdateCascade + dbRelationDeleteCascade ‘ 参照整合性の強制とカスケード設定
‘ フィールドの紐付け
Set fld = rel.CreateField(strPrimaryField)
fld.ForeignName = strForeignField
rel.Fields.Append fld
‘ リレーションの追加
db.Relations.Append rel
Debug.Print “リレーション [” & strName & “] を正常に確立しました。”
Exit Sub
ErrorHandler:
‘ エラーコードから原因を特定し、構造的にハンドリングする
Select Case Err.Number
Case 3200, 3012
MsgBox “整合性エラー: 関連テーブルに不整合なデータが含まれています。” & vbCrLf & _
“親テーブルに存在しないIDが子テーブルに存在しないか確認してください。”, vbCritical
Case Else
MsgBox “未知のエラー発生: ” & Err.Description, vbCritical
End Select
End Sub
—
3. 実務で「詰む」ポイント:3つの鉄則
このコードを実務に落とし込む際、以下の3点を意識しなければならない。
① データのクリーニングを先に行え
リレーションを張る前に、必ず「子テーブルのレコードが親テーブルに存在するか」をSQLでチェックする仕組みを入れろ。`WHERE NOT EXISTS` を使うのが最も高速だ。整合性が取れていないデータを放置したまま `db.Relations.Append` を実行するのは、地雷原を全力疾走するようなものだ。
② `Attributes` の重みを理解する
`dbRelationUpdateCascade`(更新連鎖)と `dbRelationDeleteCascade`(削除連鎖)は強力なツールだが、安易に使うな。誤って親レコードを削除した際、子レコードまで連鎖的に消える。業務要件として「履歴を残すべき」なら、カスケードは禁止し、論理削除(フラグ管理)と整合性チェックを組み合わせるのが正攻法だ。
③ インデックスの存在を確認せよ
リレーションのキーとなるフィールドには、必ずインデックスを張れ。Accessのエンジンは、インデックスのないリレーションの検証に膨大なコストを払う。テーブル定義の段階で、`TableDef` オブジェクトを操作してインデックスが定義されているか確認するルーチンを組み込むのが、真のエンジニアの流儀だ。
—
結論:コードは「ドキュメント」である
リレーションシップをVBAで制御するということは、データベースの「設計図」そのものをコードの中に埋め込むということだ。これにより、後任の開発者は「このテーブルとこのテーブルは、この制約で結ばれているのか」を一目瞭然で理解できる。
「GUIで適当に設定して動いたからOK」というレベルから脱却せよ。あなたの書くコードが、そのシステムの寿命を左右するのだ。
さあ、今すぐGUIのリレーション画面を閉じて、このスクリプトを自分のライブラリに組み込んでほしい。それが、プロの第一歩だ。
