SQLの「文字列連結」は卒業!DAO.QueryDefで安全かつ高速なクエリ実行を実現する
こんにちは。Accessの泥臭い自動化の世界へようこそ。
多くの初学者が最初にぶつかる壁、そして「中級者への登竜門」となるのが、VBAからクエリに値を渡して実行する方法です。
「SQL文を文字列として繋ぎ合わせて作る」という方法、皆さんもやっていませんか?
`strSQL = “SELECT FROM T_売上 WHERE 得意先ID = ” & Me.txtID` みたいな書き方です。
実はこれ、「SQLインジェクション」というセキュリティリスクがあるだけでなく、日付や文字列のクォーテーション管理でミスが多発する、非常に危険な橋なのです。
今日は、プロが現場で必ず使う「DAO.QueryDef」を使ったパラメータの受け渡し方法を伝授します。ここをクリアすれば、あなたのAccess開発は一気に「堅牢なシステム」へと進化しますよ。
—
なぜ「文字列連結」はダメなのか?
文字列連結でSQLを作ると、以下のような問題が発生します。
1. セキュリティリスク: 不正な文字列を注入されると、DBの中身を破壊される可能性があります。
2. バグの温床: `O’Reilly` のような名前にシングルクォーテーションが含まれていると、SQLが構文エラーで即死します。
3. パフォーマンスの低下: 毎回異なる文字列として解釈されるため、データベースエンジンが実行計画を再利用できず、処理が重くなります。
これらを一発で解決するのが、「パラメータクエリ」と「QueryDefオブジェクト」です。
—
実装の極意:DAO.QueryDefの作法
まずは、Accessのクエリデザイン画面で、パラメータを設定したクエリを作っておきましょう。
1. クエリを作成し、抽出条件に `[p_ID]` と記述して保存します(名前を `Q_売上抽出` とします)。
2. 「クエリの設定」→「パラメータ」で、`p_ID` のデータ型を「長整数型(Long)」に指定します。
これで、クエリ側は「パラメータが来るのを待つ準備」が整いました。あとはVBAから値を流し込むだけです。
【実用コード】QueryDefを使った安全な実装
Public Sub RunParameterQuery()
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim rs As DAO.Recordset
‘ CurrentDbを明示的に取得(メモリ管理の基本)
Set db = CurrentDb
‘ クエリ定義オブジェクトをセット
Set qdf = db.QueryDefs(“Q_売上抽出”)
‘ パラメータに値を安全にセット(型変換も自動で面倒を見てくれます)
qdf.Parameters(“p_ID”) = Me.txtInputID.Value
‘ レコードセットを開く(実行結果をメモリ上で操作可能)
Set rs = qdf.OpenRecordset(dbOpenDynaset)
‘ ここでデータを処理する
If Not rs.EOF Then
Debug.Print “売上合計: ” & rs!金額
End If
‘ 後処理(オブジェクトの開放は自動化エンジニアの嗜み)
rs.Close
qdf.Close
Set rs = Nothing
Set qdf = Nothing
Set db = Nothing
End Sub
—
このコードの「賢いポイント」
1. 型の安全性: `qdf.Parameters(“p_ID”) = Me.txtInputID.Value` と書くことで、VBAが自動的に型変換を行ってくれます。数値か文字列か、日付かといった「クォーテーションの悩み」から完全に解放されます。
2. 実行計画の再利用: パラメータ化されたクエリは、データベースエンジン側で最適化された実行計画をキャッシュしやすいため、大量データを扱う際のレスポンスが向上します。
3. オブジェクトの寿命管理: `Set qdf = Nothing` などを最後に行うことで、メモリリークを防ぎます。Accessの動作が徐々に重くなる…という現象の多くは、こうしたオブジェクトの解放漏れが原因です。
—
陥りやすい罠と対策
Q. パラメータ名が見つからないエラーが出る!
`qdf.Parameters(“p_ID”)` と書く際、クエリ側のパラメータ名と一文字でも違えばエラーになります。また、クエリデザイン画面で「パラメータ」の設定を忘れてもエラーになります。必ずクエリプロパティを確認してください。
Q. フォームのコントロールと直接バインドできないの?
`qdf.Parameters(“p_ID”) = Forms!F_メイン!txtID` と書くこともできますが、あまり推奨しません。VBAで一度変数に受けてからセットする方が、デバッグ時に「今、何の値が入っているか」をイミディエイトウィンドウで追跡できるため、圧倒的に保守性が高くなります。
—
最後に:プロへの道は「丁寧な後処理」から
Access VBAは、一見すると「誰でも書ける」言語です。しかし、メモリ管理(オブジェクトの解放)や、今回のようなクエリの安全な実行を疎かにすると、現場では「突然動かなくなる魔法のツール」になってしまいます。
まずは、今書いている文字列連結のコードを、一つずつこの `QueryDef` 方式に置き換えてみてください。その小さな積み重ねが、あなたを「マクロを作る人」から「システムを設計するエンジニア」へと変えてくれるはずです。
もし分からないことがあれば、いつでも聞いてください。Accessの海を渡るためのコンパスは、いつもここにありますよ。
