【入門編】【上級】循環参照を回避する複雑なリレーションシップの自動構築ロジック – Access VBA解析バイブル

スポンサーリンク

こんにちは、現場の最前線でAccessと格闘するエンジニアの皆さん。そして「マクロの記録」を卒業し、真の自動化の扉を叩こうとしている皆さん。私は皆さんの冒険をサポートする、チーフアーキテクトです。

Access VBAの世界は奥が深く、特に「テーブル定義(TableDef)」と「リレーションシップ」の自動制御は、システム構築における「屋台骨」を作る作業です。ここを自動化できるようになると、開発効率は劇的に向上し、何より「設計書通りの正確なデータベース」を一瞬で組み上げることが可能になります。

今日は、中級者から上級者へのステップアップとして避けては通れない、「複雑なリレーションシップを、依存関係を考慮して正しく構築するロジック」について、優しく、かつ深く解説していきます。

「ここをクリアすれば、Access VBAの基本はバッチリですよ」――そう自信を持って言える内容です。一緒に見ていきましょう。

1. なぜ「自動構築」にアルゴリズムが必要なのか?

通常、Accessの画面でリレーションシップを作成する際は、マウスで線を引くだけです。しかし、VBAで数十、数百のテーブルを繋ごうとすると、ある問題に直面します。

それは、「卵が先か、鶏が先か」という問題です。

  • テーブルAの外部キーが、テーブルBの主キーを参照している。
  • 参照される側のテーブル(主テーブル)が未完成だったり、主キーが設定されていなかったりすると、リレーションシップ作成はエラーになります。
  • さらに、複雑なシステムでは「循環参照(A→B→C→A)」のような構造が(本来は避けるべきですが)設計上紛れ込むこともあります。

これらを「行き当たりばったり」でコードに書くと、エラーの山に埋もれてしまいます。そこで、「定義データ」と「構築エンジン」を分離し、正しい順序で実行する知的なアプローチが必要になるのです。

2. 登場人物(オブジェクト)を理解しよう

リレーションシップを制御するために、私たちが操作する主要なオブジェクトは以下の3つです。

1. TableDef(テーブル定義): テーブルそのものの器です。
2. Field(フィールド): テーブルの中の列です。リレーションを張るには、両方のテーブルに同じ型のフィールドが必要です。
3. Relation(リレーションシップ): これが今回の主役。テーブル同士を結びつける「絆」です。

図解するとこのようなイメージです。

[主テーブル (TableDef)] [外部テーブル (TableDef)]
| |
[主キー (Field)] <---------- [外部キー (Field)] ^ ^ └----------[Relation]-------┘ ---

3. 依存関係を突破する構築アルゴリズム

エラーを防ぎ、確実にリレーションを構築するためのステップを整理しました。

1. 既存リレーションの全削除: 構築前に一度クリアにします(更新のため)。
2. テーブルとフィールドの存在確認: 参照先が存在しないのにリレーションは張れません。
3. リレーションの定義情報をリスト化: どのテーブルのどの項目を繋ぐかをデータ化します。
4. 安全な順序での実行:

  • まずはテーブルだけをすべて作る。
  • 次にインデックス(主キー)をすべて設定する。
  • 最後にリレーションシップを一気に張る。

この「3段階のフェーズ」に分けることで、依存関係のトラブルの大部分を回避できます。

4. 【実践】リレーションシップ自動構築コード

それでは、実際に使えるコードを見てみましょう。このコードは、リレーションシップの情報を配列や一時的なリストとして持ち、それを順番に処理するプロフェッショナルな構成になっています。

‘ =========================================================
‘ 業務自動化エンジニア直伝:リレーションシップ構築ロジック
‘ =========================================================
Public Sub BuildDatabaseSchema()
Dim db As DAO.Database
Set db = CurrentDb

On Error GoTo ErrorHandler

Debug.Print “— スキーマ構築開始 —”

‘ STEP 1: 既存のリレーションシップを安全に削除
‘ 依存関係があるため、まずはリレーションシップだけをすべて消します
DeleteAllRelations db

‘ STEP 2: リレーションシップの作成
‘ ここでは例として2つのテーブルを繋ぎますが、
‘ 実際にはループや設定テーブルから読み込む形に応用できます。

‘ 例: [T_注文] から [T_顧客] へのリレーションを作成
‘ 引数: (データベース, リレーション名, 主テーブル, 外部テーブル, 主キー, 外部キー)
CreateRelationSafely db, “Rel_Order_Customer”, “T_顧客”, “T_注文”, “顧客ID”, “顧客ID”

‘ 例: [T_注文詳細] から [T_注文] へのリレーションを作成
CreateRelationSafely db, “Rel_OrderDetail_Order”, “T_注文”, “T_注文詳細”, “注文ID”, “注文ID”

Debug.Print “— スキーマ構築完了 —”
MsgBox “データベース構造の再構築に成功しました!”, vbInformation

Exit Sub

ErrorHandler:
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical
End Sub

‘ ———————————————————
‘ 既存のリレーションシップをすべて削除するサブ関数
‘ ———————————————————
Private Sub DeleteAllRelations(db As DAO.Database)
Dim rel As DAO.Relation
Dim i As Integer

‘ Relationコレクションを後ろからループして削除するのがコツです
For i = db.Relations.Count – 1 To 0 Step -1
db.Relations.Delete db.Relations(i).Name
Next i
Debug.Print “既存のリレーションシップをクリアしました。”
End Sub

‘ ———————————————————
‘ 個別のリレーションシップを安全に作成するサブ関数
‘ ———————————————————
Private Sub CreateRelationSafely(ByRef db As DAO.Database, _
strName As String, _
strPrimaryTable As String, _
strForeignTable As String, _
strPrimaryKey As String, _
strForeignKey As String)
Dim rel As DAO.Relation
Dim fld As DAO.Field

‘ 1. Relationオブジェクトの器を作成
Set rel = db.CreateRelation(strName, strPrimaryTable, strForeignTable)

‘ 2. 参照整合性と、連動更新・連動削除の属性を設定
‘ dbRelationUpdateCascade: 更新連動
‘ dbRelationDeleteCascade: 削除連動
‘ dbRelationLeft: 参照整合性を維持
rel.Attributes = dbRelationUpdateCascade + dbRelationDeleteCascade

‘ 3. リレーションを構成するフィールドを追加
‘ 注意:この時点ではまだRelationはDBに保存されていません
Set fld = rel.CreateField(strPrimaryKey) ‘ 主テーブルのキー
fld.ForeignName = strForeignKey ‘ 外部テーブルのキー
rel.Fields.Append fld

‘ 4. DatabaseのRelationsコレクションに追加して確定
db.Relations.Append rel

Debug.Print “作成成功: ” & strName
End Sub

5. ここがポイント!エンジニアの知恵袋

① `Delete` は「後ろから」が鉄則

コードの中で `For i = db.Relations.Count – 1 To 0 Step -1` としているのに気づきましたか?
コレクションからアイテムを削除するとき、前から消すとインデックスがズレてしまい、すべてのアイテムを消しきれない「お化けバグ」に遭遇します。これはAccess VBAに限らず、あらゆるプログラミングに通ずる基本テクニックです。

② `Attributes` プロパティの魔術

`rel.Attributes = dbRelationUpdateCascade + dbRelationDeleteCascade`
この一行が、Accessの強力な「参照整合性」を制御しています。

  • 更新連動: 親のIDを変えたら子も変わる。
  • 削除連動: 親を消したら子も消える。

これをコードで制御することで、ユーザーの操作ミスによるデータ不整合を未然に防ぐ「堅牢なシステム」が完成します。

③ 循環参照を回避するには?

もし設計上、どうしても A→B→C→A のような関係が必要な場合(※推奨はしません)、リレーションシップの作成順序を工夫するのではなく、「どこか一つのリレーションシップで『参照整合性』をチェックしない(Attributesを設定しない)」ことで、Accessの制約を回避できます。しかし、まずはデータモデルの設計を見直すのが、一流のエンジニアの仕事です。

最後に:一歩ずつ、確実に。

リレーションシップの自動構築は、最初は難しく感じるかもしれません。でも、今回紹介した「器を作って、中身を詰めて、最後に追加(Append)する」という流れを理解すれば、どんな複雑なテーブル構造も自由自在に操れるようになります。

「ここをクリアすれば、Access VBAの基本はバッチリですよ」

あなたが書くそのコード一行一行が、システムの未来を支える強固な土台になります。エラーを恐れず、このロジックを自分のものにしてください。もし迷ったら、いつでもこの記事に戻ってきてくださいね。

あなたの開発現場が、より創造的で楽しいものになることを願っています!

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