Accessの闇を切り裂く:QueryDefにおける「直接参照」という名の技術的負債を断つ
Access VBAで業務アプリを構築する際、誰もが一度は通る道がある。クエリのSQL文の中に `Forms!frm_Sales!txt_StartDate` と書き込む、あの手軽な手法だ。
「動くからいいだろう」と放置している諸君、そのコードは「保守性の地雷」であり「パフォーマンスの搾取」そのものだ。今日は、なぜその書き方がエンジニアリングとして三流なのか、そしてプロの現場で生き残るための「パラメータオブジェクト」を活用した最適解を授ける。
—
なぜ `Forms!名前!コントロール` を直接書くべきではないのか
SQL文の中に直接フォーム上のコントロールを参照させる書き方は、一見するとコード量が減るように思える。だが、この設計には致命的な欠陥が3つある。
1. 疎結合の破壊: クエリ定義(QueryDef)が特定のフォームの存在に依存してしまう。フォーム名を変更したり、別画面から同じクエリを呼び出そうとした瞬間に破綻する。
2. 実行計画の最適化阻害: Jet/ACEデータベースエンジンは、パラメータが明示されていないSQLを解析する際、実行のたびに構文解析コストを支払う。複雑なクエリになればなるほど、この「再コンパイル」が積み重なり、大規模データでは致命的な遅延を招く。
3. デバッグの困難さ: SQLがエンジンの外部(フォーム)と密接に絡み合うため、VBAのイミディエイトウィンドウでSQLをダンプしても、値が解決されず「何が投げられているのか」が見えなくなる。
—
聖杯:パラメータオブジェクト(Parameters Collection)による堅牢な設計
プロのコードは、「SQL文」と「値の注入」を明確に分離する。 これが、変更に強く、高速で、デバッグが容易なアーキテクチャの鉄則だ。
実践:QueryDefのパラメータを明示的に注入するコード
以下のコードは、既存のクエリ定義(`qry_SearchSales`)に対して、フォームの値を安全に受け渡すテンプレートだ。これをモジュールに実装せよ。
‘ ———————————————————
‘ 関数名: ExecuteDynamicQuery
‘ 概要: QueryDefのパラメータを明示的に解決し、堅牢に実行する
‘ ———————————————————
Public Sub ExecuteDynamicQuery()
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim prm As DAO.Parameter
Set db = CurrentDb
‘ クエリ定義を取得(あらかじめSQL内には「[p_StartDate]」のようなプレースホルダーを置く)
Set qdf = db.QueryDefs(“qry_SearchSales”)
‘ パラメータに値をセットする(重要:フォームへの依存をここで完結させる)
‘ SQL内のパラメータ名と完全に一致させること
With qdf
.Parameters(“p_StartDate”) = Forms!frm_Sales!txt_StartDate.Value
.Parameters(“p_EndDate”) = Forms!frm_Sales!txt_EndDate.Value
‘ 結果をレコードセットとして取得、あるいはアクションクエリなら .Execute
Dim rs As DAO.Recordset
Set rs = .OpenRecordset(dbOpenSnapshot)
‘ — ここにデータ処理ロジックを記述 —
rs.Close
End With
‘ オブジェクトのクリーンアップ
Set rs = Nothing
Set qdf = Nothing
Set db = Nothing
End Sub
—
現場で生き残るための「3つの極意」
1. SQL内でのプレースホルダー命名規則
SQL文では `[p_StartDate]` のように、先頭に `p_` などの識別子を付ける癖をつけろ。これにより、コードレビュー時に「これは動的なパラメータである」と一目で判別できる。
2. データ型の明示的キャスト
VBAは柔軟だが、それが仇になる。パラメータを渡す際は、必ず `.Value` を指定し、必要に応じて `CDate()` や `CLng()` で型を確定させること。Accessのエンジンが「型変換を推測する」時間を節約させるのが、高速化の第一歩だ。
3. エラーハンドリングの徹底
動的クエリは「フォームが閉じている」「入力値が空」という状況に弱い。`Parameters` に値を注入する前に、必ず「そのフォームが開いているか」「値が妥当か」のチェックを `If CurrentProject.AllForms(“frm_Sales”).IsLoaded Then` 等で行うガード句を忘れずに実装せよ。
—
最後に:エンジニアとしての矜持
「動けばいい」という考え方は、数千件のデータで止まるシステムの種になる。
諸君が書くその一行のVBAが、半年後の自分、あるいは後任のエンジニアを苦しめるのか、それとも感謝させるのかは、この「疎結合な設計」を徹底できるかどうかにかかっている。
クエリは、フォームのしもべではない。独立したロジックだ。
この設計思想をインストールし、堅牢で美しいAccess開発を実現してほしい。健闘を祈る。
