【Access VBA極意】巨大なフラットテーブルを「正規化」する自動移行術
こんにちは。Accessの迷宮を探索する皆さんの道標となるべく、今日も筆を執りました。
Accessで開発をしていると、避けて通れないのが「誰かが作った、巨大で管理不能なフラットテーブル」との遭遇です。Excelの延長で設計されたそのテーブルは、データが増えるほど動作は重くなり、重複データで整合性はボロボロ。
今回は、そんな「負の遺産」を、VBAを使ってスマートに正規化(テーブル分割)し、リレーションシップまで再構築するという、まさに「エンジニアの腕の見せ所」とも言えるプロジェクトを解説します。
—
1. なぜ「手作業」ではなく「VBA」なのか?
数千行のテーブルなら手作業でもなんとかなるかもしれません。しかし、数万行を超え、かつ今後も運用が続くシステムであれば、手作業は「ミス」の温床です。
VBAを使う最大のメリットは「再現性」と「検証可能性」です。
1. 処理のログが残る: 何が起きているかコードとして可視化される。
2. 何度でもやり直せる: 失敗したらテーブルを削除してスクリプトを再実行するだけ。
3. リレーションシップの自動化: 手動で線を引く際の「設定ミス」を防げる。
これらをクリアすれば、あなたはもう「マクロの記録」に頼る初心者ではありません。Accessの心臓部を直接操作できるエンジニアへの第一歩です。
—
2. 実践:正規化自動化スクリプト
今回は、例として「注文管理テーブル(注文ID、顧客名、顧客電話番号、商品名、単価)」を、「注文テーブル」と「顧客テーブル」に分離するシナリオを想定します。
事前準備
- `DAO`ライブラリを参照設定してください(VBAエディタのツール > 参照設定 > 「Microsoft Office 16.0 Access database engine Object Library」にチェック)。
Sub NormalizeTables()
Dim db As DAO.Database
Dim rsSource As DAO.Recordset
Dim strSQL As String
Set db = CurrentDb
‘ 1. 顧客テーブルを作成(重複を排除して抽出)
‘ DISTINCTでユニークな顧客情報を抜き出すのがポイント
strSQL = “SELECT DISTINCT 顧客名, 顧客電話番号 INTO T_顧客 FROM T_注文管理;”
db.Execute strSQL, dbFailOnError
‘ 2. 顧客テーブルに主キー(ID)を付与
db.Execute “ALTER TABLE T_顧客 ADD COLUMN 顧客ID COUNTER CONSTRAINT PK_顧客 PRIMARY KEY;”, dbFailOnError
‘ 3. 注文テーブルの準備(顧客IDを紐付ける)
‘ ここでは設計の簡略化のため、既存テーブルから顧客名を残しつつIDを付与する手順へ
‘ 本来は顧客IDをルックアップして更新する複雑な処理が必要ですが、まずはここから!
MsgBox “テーブルの分割準備が完了しました。”, vbInformation
End Sub
—
3. リレーションシップをVBAで構築する
テーブルを分けただけでは意味がありません。Accessのデータベースエンジンに「このテーブルとあのテーブルは繋がっているよ」と教える必要があります。これを`Relation`オブジェクトで行います。
Sub CreateRelationship()
Dim db As DAO.Database
Dim rel As DAO.Relation
Dim fld As DAO.Field
Set db = CurrentDb
‘ リレーションの定義(T_顧客.顧客ID -> T_注文.顧客ID)
Set rel = db.CreateRelation(“顧客と注文”, “T_顧客”, “T_注文”, dbRelationUpdateCascade)
‘ 紐付けるフィールドを指定
Set fld = rel.CreateField(“顧客ID”)
fld.ForeignName = “顧客ID”
rel.Fields.Append fld
‘ リレーションをDBに登録
db.Relations.Append rel
MsgBox “リレーションシップが正常に構築されました。”, vbInformation
End Sub
—
4. 初学者が陥りやすい「3つの落とし穴」
コードを書いていて「動かない!」となったとき、以下のポイントをチェックしてください。
1. 排他制御の罠:
対象のテーブルを「開いたまま」コードを実行していませんか?VBAはテーブルを直接操作するため、他の画面で開いているとエラーになります。`CurrentDb.TableDefs`を触る際は、必ずすべてのウィンドウを閉じてください。
2. データ型の不整合:
正規化の際、元データの「顧客ID」が文字列型で、リンク先の「顧客ID」が数値型になっていると、リレーションは作成できません。`ALTER TABLE`で列を追加する際、データ型を厳密に定義してください。
3. 「とりあえず実行」の恐怖:
`db.Execute`を使う際は、必ずバックアップを取ってください。正規化のスクリプトは破壊的な操作を含みます。`CurrentDb.Execute`の前に、今一度「このテーブルを消して大丈夫か?」と自問する勇気も、一流の証です。
—
最後に:エンジニアとして成長するために
今回紹介したコードは、あくまで「最初の一歩」です。実務では、ここからさらに「エラーハンドリング(`On Error GoTo`)」を組み込み、処理がどこで止まったかをログファイルに出力する仕組みへと進化させていく必要があります。
AccessのVBAは、単なる事務効率化ツールではありません。「データの構造を正しく定義し、整合性を守るためのアーキテクトツール」です。
テーブルを美しく分割できたとき、あなたの作ったシステムは「ただ動くもの」から「壊れにくい堅牢な資産」へと変わります。ぜひ、このコードをベースに、自分だけの自動化ツールを育て上げてください。
応援していますよ。困ったことがあれば、またいつでも聞きに来てくださいね。
