【実務・中級編】QueryDefの「説明文(Description)」プロパティを活用したSQLドキュメントの自動生成 – Access VBA解析バイブル

スポンサーリンク

Access VBAを掌握する極限の知見:QueryDefの「説明文」をハックしてシステム仕様書を自動生成する技術

システム開発の現場で、最も不毛かつ泥臭い作業の一つが「データベース仕様書の作成と維持」ではないか。
Accessを用いた業務システムにおいて、数多のクエリが乱立し、「このクエリ、誰が何の目的で作ったんだ?」「消したらどこが壊れる?」と頭を抱えた経験は、開発者なら一度や二度ではないはずだ。

Excelで仕様書を手動メンテする? ――ナンセンスだ。
コードやクエリの変更と仕様書の同期が取れなくなるのは、エンジニアの怠慢ではなく、「ドキュメントを別の場所に置くという設計の欠陥」にある。

Accessには、クエリ定義(QueryDef)オブジェクトそのものに「説明文(Description)」を保持するネイティブな領域が存在する。今回は、この隠れたプロパティを徹底的にハックし、クエリのメタデータから一瞬で最新のシステム仕様書を自動生成する、プロダクション品質のアーキテクチャを伝授する。

—

なぜ「QueryDef.Properties(「説明文」)」なのか?

多くの開発者は、クエリの目的や仕様を残すために、SQL文の中にコメント(`–` や `/ /`)を書いたり、別紙のExcel管理台帳に頼ったりする。しかし、これは以下の理由から実務では破綻する。

1. SQLのコメントは一覧性が低い:クエリを開いて中身を見なければ確認できない。
2. Excel台帳は必ず陳腐化する:クエリを修正したエンジニアが、Excel側の更新を忘れるのは歴史の必然である。

ここで登場するのが、DAO(Data Access Objects)の `QueryDef` が持つ `Properties` コレクションである。実は、Accessのナビゲーションウインドウでクエリを右クリックし、「プロパティ」を開いたときに入力する「説明文」は、DAOのコードからは `”Description”` プロパティ として直接読み書きできる。

クエリの「中身(SQL)」と「説明(メタデータ)」をデータベースファイル(ACCDB)という単一のコンテナ内にカプセル化する。これこそが、保守性を極限まで高めるための正しい設計思想なのだ。

—

堅牢な設計における罠:存在しないプロパティの恐怖

ここで一つ、Access VBA特有の深い罠について警告しておかなければならない。

`QueryDef.Properties(“Description”)` は、クエリが作成された直後や、一度も手動・コードで説明文が設定されていない状態では、プロパティコレクション自体に存在しない。

もし存在しないプロパティへ直接アクセスすれば、容赦なく「実行時エラー ‘3270’: プロパティが見つかりません」が発生する。
したがって、堅牢なコードを書くためには、以下の2つのアプローチのいずれかを採用する必要がある。

1. プロパティの有無を動的に判定し、なければ新規作成(`CreateProperty`)して追加する。
2. エラーハンドリングを活用して安全に取得・設定する。

今回は、プロダクションコードとして恥ずかしくない、前者の「動的プロパティ生成・安全アクセス機構」を組み込んだ実装を公開する。

—

実装:クエリ仕様書自動生成モジュール

以下のコードは、現在のデータベース内に存在するすべてのユーザー定義クエリを走査し、その名前、SQL、そして「説明文」を抽出し、一括でExcelワークシート(または新規ブック)へ出力するプロシージャである。

実務でそのままコピー&ペーストしてモジュールに貼り付け、実行してほしい。

Option Compare Database
Option Explicit

‘ =========================================================================
‘ módulo名: basQuerySpecificationGenerator
‘ 概要 : QueryDefの説明文プロパティを活用し、クエリ仕様書をExcelへ自動出力する
‘ =========================================================================
Public Sub GenerateQuerySpecification()
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim xlApp As Object
Dim xlBook As Object
Dim xlSheet As Object
Dim rowIdx As Long
Dim descText As String

On Error GoTo ErrorHandler

Set db = CurrentDb

‘ Excelのインスタンスを生成(早期バインディング推奨だが環境依存を避けるため遅延バインディング)
Set xlApp = CreateObject(“Excel.Application”)
xlApp.Visible = True
Set xlBook = xlApp.Workbooks.Add
Set xlSheet = xlBook.Sheets(1)
xlSheet.Name = “クエリ仕様書”

‘ — ヘッダーの作成 —
With xlSheet
.Cells(1, 1).Value = “クエリ名”
.Cells(1, 2).Value = “クエリタイプ”
.Cells(1, 3).Value = “説明文 (Description)”
.Cells(1, 4).Value = “SQLステートメント”

‘ ヘッダーの書式設定
.Range(“A1:D1”).Font.Bold = True
.Range(“A1:D1”).Interior.Color = RGB(220, 230, 242)
End With

rowIdx = 2

‘ — クエリ走査ループ —
For Each qdf In db.QueryDefs
‘ システムクエリ(~で始まる一時クエリなど)は除外する
If Left(qdf.Name, 1) <> “~” Then

‘ 説明文プロパティを安全に取得する関数を呼び出し
descText = GetQueryDescription(qdf)

‘ Excelに出力
xlSheet.Cells(rowIdx, 1).Value = qdf.Name
xlSheet.Cells(rowIdx, 2).Value = GetQueryTypeName(qdf.Type)
xlSheet.Cells(rowIdx, 3).Value = descText
xlSheet.Cells(rowIdx, 4).Value = qdf.SQL

rowIdx = rowIdx + 1
End If
Next qdf

‘ — 仕上げ(列幅の自動調整とグリッド線) —
xlSheet.Columns(“A:D”).AutoFit
xlApp.Visible = True

MsgBox “クエリ仕様書の自動生成が完了しました。”, vbInformation, “完了”

CleanUp:
‘ オブジェクトの解放
Set qdf = Nothing
Set db = Nothing
Set xlSheet = Nothing
Set xlBook = Nothing
Set xlApp = Nothing
Exit Sub

ErrorHandler:
MsgBox “予期せぬエラーが発生しました。” & vbCrLf & _
“Error No: ” & Err.Number & vbCrLf & _
“Description: ” & Err.Description, vbCritical, “エラー”
Resume CleanUp
End Sub

‘ =========================================================================
‘ 関数名: GetQueryDescription
‘ 概要 : QueryDefから安全にDescriptionプロパティを取得する。
‘ 存在しない場合は空文字を返す。
‘ =========================================================================
Private Function GetQueryDescription(ByRef qdf As DAO.QueryDef) As String
Dim prop As DAO.Property
Dim desc As String

On Error GoTo CheckError

desc = qdf.Properties(“Description”)
GetQueryDescription = desc
Exit Function

CheckError:
‘ プロパティが存在しないエラー (3270) の場合は空文字を返す
If Err.Number = 3270 Then
GetQueryDescription = “”
Else
‘ その他の予期せぬエラーはそのままスロー
Err.Raise Err.Number, Err.Source, Err.Description
End If
End Function

‘ =========================================================================
‘ 関数名: SetQueryDescription
‘ 概要 : 特定のクエリに説明文を設定・更新する(保守用ユーティリティ)
‘ =========================================================================
Public Sub SetQueryDescription(ByVal queryName As String, ByVal descriptionText As String)
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim prop As DAO.Property

Set db = CurrentDb
Set qdf = db.QueryDefs(queryName)

On Error GoTo CreateProp

‘ すでにプロパティが存在する場合は値を更新
qdf.Properties(“Description”) = descriptionText
GoTo CleanUp

CreateProp:
If Err.Number = 3270 Then
‘ プロパティが存在しないので新規作成して追加
Set prop = qdf.CreateProperty(“Description”, dbText, descriptionText)
qdf.Properties.Append prop
Resume Next
Else
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical
End If

CleanUp:
Set prop = Nothing
Set qdf = Nothing
Set db = Nothing
End Sub

‘ =========================================================================
‘ 関数名: GetQueryTypeName
‘ 概要 : クエリのタイプ定数を人間が読める文字列に変換する
‘ =========================================================================
Private Function GetQueryTypeName(ByVal qType As Integer) As String
Select Case qType
Case 0: GetQueryTypeName = “選択クエリ (Select)”
Case 16: GetQueryTypeName = “クロス集計クエリ (Crosstab)”
Case 32: GetQueryTypeName = “削除クエリ (Delete)”
Case 48: GetQueryTypeName = “更新クエリ (Update)”
Case 64: GetQueryTypeName = “追加クエリ (Append)”
Case 80: GetQueryTypeName = “テーブル作成クeri (Make-Table)”
Case 112: GetQueryTypeName = “パススルー (Pass-Through)”
Case 128: GetQueryTypeName = “データ定義 (Data Definition)”
Case 144: GetQueryTypeName = “ユニオンクエリ (Union)”
Case Else: GetQueryTypeName = “その他 (” & qType & “)”
End Select
End Function

—

このアーキテクチャがもたらす現場の変革

この仕組みを導入した開発現場では、以下のような強烈なメリットが生まれる。

1. ドキュメントの鮮度が100%保たれる
クエリの改修と同時に、Accessのプロパティ(あるいは用意した管理用フォームから `SetQueryDescription` を呼ぶ形)で説明文をメンテする文化さえ根付けば、いつでもワンクリックで「生きた最新の仕様書」をExcelに出力できる。
2. ナレッジの属人化を防ぐ
新規参画した開発者や、引き継ぎを受けた担当者が、複雑なパラメータークエリや集計クエリの意図を迷うことなくコードレベル・オブジェクトレベルで把握できる。
3. ファイル連携・デプロイ時の耐性
バックエンドデータベース(BE)とフロントエンドデータベース(FE)を分離しているアーキテクチャの場合、クエリは通常FE側に存在する。このコードは `CurrentDb`(つまり接続中のFE)を走査するため、ローカルのクエリ設計書を瞬時にビルドするのに最適である。

—

チーフアーキテクトからの提言

コードを書いて終わり、動いて終わり、の時代は終わった。プロフェッショナルなエンジニアが目指すべきは、「後続の人間がメンテナンスに苦しまない自走するエコシステムの構築」である。

QueryDefの「説明文」という、普段光の当たらない地味なプロパティ。ここに目をつけ、メタデータとして活用することこそが、Access開発を「レガシーな泥沼」から「洗練されたエンタープライズ開発」へと昇華させる鍵となる。

あなたのプロジェクトでも、今すぐこの仕組みを取り入れ、手動のドキュメント作成という悪習に終止符を打ってほしい。

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