【プロ】メタデータ駆動型開発:Excel定義書からテーブルを自動生成するエンジン
開発現場でこんな不毛な作業に時間を溶かしていないだろうか。
「Excelの設計書を見ながら、Accessの画面でポチポチとテーブルを作り、フィールド名を入力し、データ型をドロップダウンから選び、インデックスを設定する……」
仕様変更のたびにテーブルを削除し、作り直し。数ならまだしも、数十テーブルにおよぶエンティティをこの手作業で構築・修正するのは、エンジニアのキャリアの無駄遣いだ。何より、ヒューマンエラー(入力ミス)の温床となる。
プロの業務自動化エンジニアが選ぶべき道は一つしかない。「メタデータ駆動型開発(Metadata-Driven Development)」だ。
Excelに記述されたテーブル定義書を“データ(メタデータ)”として読み込み、VBAのDAO(Data Access Object)を駆使して一瞬でデータベース構造を自動構築・同期するエンジンを自作する。
今回は、実務の現場でそのまま稼働する、堅牢かつ洗練されたテーブル自動生成エンジンの全貌を伝授しよう。
—
なぜ「手動作成」と「安易なSQL実行」は破綻するのか?
まず、設計思想の話をしておこう。
「CREATE TABLE文のSQLをVBAで組み立てて実行すればいいのでは?」と考えたそこのあなた。実務の巨大なデータベースを舐めてもらっては困る。
純粋なSQLの `CREATE TABLE` だけでは、以下の要件を満たすのが極めて困難、あるいはコードが複雑化してスパゲッティ化する。
1. 長いテキスト型やリレーションシップ(外部キー制約)の確実な付与
2. 既存テーブルが存在する場合の「安全な改修・差分更新」
3. プロパティ(書式、入力規則、既定値など)のきめ細やかな制御
DAO(Data Access Object)の `TableDef` および `Field` オブジェクトを直接操作するアプローチこそが、Accessの内部構造に最もミートし、かつエラーハンドリングもしやすい最強の手段なのだ。
—
アーキテクチャの全体像
今回構築するエンジンの仕組みはこうだ。
1. マスター定義Excelを用意する
一つのExcelブックに「テーブル定義一覧(TableList)」と「フィールド定義詳細(FieldList)」の2つのシートを持たせる。
2. ADOでExcelを読み込む
Access側からExcelを起動するのではなく、ADO(ActiveX Data Objects)を使って高速かつバックグラウンドでExcelの定義をレコードセットとして吸い上げる。
3. DAOでテーブル・フィールドを動的生成
読み込んだメタデータをループさせ、DAOを用いてテーブルの有無を判定しながら、存在しなければ新規作成、存在すればフィールドの追加・型変更を行う。
—
プロダクションコード:自動生成エンジン本体
以下のコードを、Accessの標準モジュールにそのまま貼り付けてほしい。実務での耐障害性を考慮し、トランザクションと厳格なエラーハンドリングを組み込んである。
Option Compare Database
Option Explicit
‘ =========================================================================
‘ 処理名 : メタデータ駆動型 テーブル自動生成エンジン
‘ 概要 : Excel定義書を読み込み、Accessのテーブル構造を自動構築する
‘ 前提 : 参照設定に「Microsoft ActiveX Data Objects x.x Library」を追加
‘ =========================================================================
Public Sub GenerateTablesFromExcel()
On Error GoTo ErrorHandler
Dim excelPath As String
excelPath = CurrentProject.Path & “\TableDefinitions.xlsx” ‘ 定義書のパス
If Dir(excelPath) = “” Then
MsgBox “テーブル定義書が見つかりません: ” & vbCrLf & excelPath, vbCritical, “致命的エラー”
Exit Sub
End If
Dim conn As Object
Dim rsTables As Object
Dim rsFields As Object
‘ ADO接続文字列(ACE OLEDB 12.0を使用)
Dim connStr As String
connStr = “Provider=Microsoft.ACE.OLEDB.12.0;Data Source=” & excelPath & _
“;Extended Properties=””Excel 12.0 Xml;HDR=YES;IMEX=1″”;”
Set conn = CreateObject(“ADODB.Connection”)
conn.Open connStr
‘ 1. テーブル定義一覧を取得
Set rsTables = CreateObject(“ADODB.Recordset”)
rsTables.Open “SELECT FROM [TableList$]”, conn, 3, 1 ‘ adOpenStatic, adLockReadOnly
Dim db As DAO.Database
Set db = CurrentDb
db.Execute “DBEngine.BeginTrans”, dbFailOnError ‘ トランザクション開始
Do Until rsTables.EOF
Dim tableName As String
tableName = Nz(rsTables(“TableName”).Value, “”)
If tableName <> “” Then
Call BuildSingleTable(db, conn, tableName)
End If
rsTables.MoveNext
Loop
db.Execute “DBEngine.CommitTrans”
rsTables.Close
conn.Close
MsgBox “テーブルの自動生成・同期が正常に完了しました。”, vbInformation, “完了”
Exit Sub
ErrorHandler:
On Error Resume Next
db.Execute “DBEngine.Rollback”
If Not rsTables Is Nothing Then If rsTables.State = 1 Then rsTables.Close
If Not conn Is Nothing Then If conn.State = 1 Then conn.Close
MsgBox “予期せぬエラーが発生しました。” & vbCrLf & _
“Error: ” & Err.Description, vbCritical, “エラー”
End Sub
‘ =========================================================================
‘ 個別テーブル構築サブルーチン
‘ =========================================================================
Private Sub BuildSingleTable(db As DAO.Database, conn As Object, tableName As String)
Dim tdef As DAO.TableDef
Dim fld As DAO.Field
Dim rsFields As Object
Dim isNewTable As Boolean
‘ テーブルの存在確認
isNewTable = False
On Error Resume Next
Set tdef = db.TableDefs(tableName)
If Err.Number <> 0 Then
isNewTable = True
Set tdef = db.CreateTableDef(tableName)
End If
On Error GoTo 0
‘ フィールド定義の取得(該当テーブルの分のみ抽出)
Set rsFields = CreateObject(“ADODB.Recordset”)
rsFields.Open “SELECT FROM [FieldList$] WHERE TableName = ‘” & tableName & “‘ ORDER BY FieldOrder”, conn, 3, 1
Do Until rsFields.EOF
Dim fldName As String
Dim fldType As Integer
Dim fldSize As Long
Dim isReq As Boolean
Dim isPK As Boolean
fldName = rsFields(“FieldName”).Value
fldType = GetDAODataType(rsFields(“DataType”).Value)
fldSize = Nz(rsFields(“FieldSize”).Value, 0)
isReq = Nz(rsFields(“IsRequired”).Value, False)
isPK = Nz(rsFields(“IsPrimaryKey”).Value, False)
‘ フィールドが既に存在するか確認
Dim fldExists As Boolean
fldExists = False
If Not isNewTable Then
On Error Resume Next
Set fld = tdef.Fields(fldName)
If Err.Number = 0 Then fldExists = True
On Error GoTo 0
End If
If Not fldExists Then
‘ フィールド新規追加
Set fld = tdef.CreateField(fldName, fldType)
If fldSize > 0 And (fldType = dbText Or fldType = dbChar) Then
fld.Size = fldSize
End If
fld.Required = isReq
‘ 主キー設定(必要に応じて)
If isPK Then
fld.Attributes = fld.Attributes Or dbAutoIncrField ‘ 必要ならオートナンバー化
End If
tdef.Fields.Append fld
End If
rsFields.MoveNext
Loop
rsFields.Close
‘ 新規テーブルの場合はTableDefsコレクションに追加
If isNewTable Then
db.TableDefs.Append tdef
End If
‘ 主キーのインデックス設定(DAOではテーブル追加後にインデックスを構築するのが安全)
‘ ※実務ではPK制約の構築ロジックをここに追記する
End Sub
‘ =========================================================================
‘ 文字列のデータ型を DAO の定数に変換するマッパー関数
‘ =========================================================================
Private Function GetDAODataType(typeName As String) As Integer
Select Case UCase(Trim(typeName))
Case “LONG”, “INTEGER”, “INT”: GetDAODataType = dbLong
Case “TEXT”, “STRING”: GetDAODataType = dbText
Case “MEMO”, “LONGTEXT”: GetDAODataType = dbMemo
Case “DATE”, “DATETIME”: GetDAODataType = dbDate
Case “CURRENCY”: GetDAODataType = dbCurrency
Case “BOOLEAN”, “BOOL”: GetDAODataType = dbBoolean
Case “DOUBLE”: GetDAODataType = dbDouble
Case Else: GetDAODataType = dbText ‘ デフォルト
End Select
End Function
—
現場で絶対にハマる「落とし穴」とプロの対策
このコードを実務に導入する際、開発者が必ず直面する壁と、その回避策を共有しておこう。
1. Excelファイルの排他制御(プロセスロック)
Excelを開きっぱなしの状態でVBAを実行すると、ADOがファイルにアクセスできずエラー(「別のプロセスで使用されています」)になる。
対策: エンジン実行前に、Excelファイルが開かれていないかをチェックするか、VBA側で一時フォルダにファイルをコピーしてから読み込ませるのが極めてスマートだ。
2. データ型マッピングの厳密性
Excelのセルは「文字列」として入力されがちだ。定義書に `TEXT(50)` と書かれているのか、単に `Text` と書かれているのか、パース処理(`GetDAODataType`)で揺れが生じやすい。
対策: 定義書のデータ型項目は、ドロップダウンリスト(入力規則)で選択式に強制し、余計な揺れを排除すること。これがメタデータ駆動型開発の鉄則である。
3. 既存データへの影響(破壊的変更の防止)
すでに運用が始まっているデータベースに対してこのエンジンを走らせた場合、既存のフィールドを誤って削除・上書きしてしまい、現場のデータを吹き飛ばすリスクがある。
プロの知見: 本番環境に適用する場合は、「既存テーブルの構造変更(ALTER相当)」ではなく、「新規追加のみを許可するセーフモード」のフラグを設けること。あるいは、開発環境(ローカル)での初期構築・バージョンアップ専用として割り切るべきだ。
—
まとめ:自動化の先にある「真のゴール」
Excel定義書からのテーブル自動生成エンジンを導入することで、開発スピードは劇的に向上するだけでなく、「仕様書がそのまま動くシステムの実装になる」というドキュメントとコードの乖離(アンシンク)を防ぐ最強のガバナンスが手に入る。
手作業でのコーディングや、画面でのマウス操作に頼る時代は終わった。
データを支配する者が、システム開発を制す。ぜひ自社のプロジェクトにこのエンジンを組み込み、圧倒的な生産性を体感してほしい。
