【入門編】QueryDefのSQLプロパティを「動的生成」する際の文字列連結を劇的に簡素化するヘルパークラスの設計 – Access VBA解析バイブル

スポンサーリンク

ようこそ、Access VBAの深淵へ。私はあなたの冒険を支えるチーフアーキテクトです。

Accessでの開発を進めていくと、必ずぶつかる大きな壁があります。それは「ユーザーの入力条件に合わせて、実行するSQLを動的に変えたい」という場面です。

多くの人が、コードの中で `strSql = strSql & ” WHERE …”` と、延々と文字列を繋ぐ「文字列結合の迷宮」に迷い込み、クォーテーションの数やスペースの入れ忘れで数時間を溶かしてしまいます。

今日は、その迷宮を脱出し、誰が見ても美しく、メンテナンスしやすいSQL生成を実現する「StringBuilderパターンのヘルパークラス」を伝授しましょう。ここをマスターすれば、あなたのAccess開発は「マクロの延長」から「プロフェッショナルなソフトウェア開発」へと進化します。

—

1. なぜ「QueryDef」と「動的SQL」の相性は最悪なのか?

Accessには、作成済みのクエリを管理する `QueryDef` というオブジェクトがあります。これは実行速度が速く、非常に優秀な仕組みです。

しかし、VBAから `QueryDef.SQL` を書き換えようとすると、途端にコードが汚くなります。

‘ よくある「悪い」例:読みづらく、バグの温床
strSql = “SELECT FROM T_在庫 ”
strSql = strSql & “WHERE 商品名 LIKE ‘” & Me.txtSearch & “‘ ”
If Me.chkOnlyStock.Value = True Then
strSql = strSql & “AND 在庫数 > 0 ”
End If
‘ ↑ スペースが足りなかったり、ANDの条件管理が複雑になると破綻する

このような「その場しのぎの連結」を卒業するために、SQLを組み立てる専用の道具(クラス)を作りましょう。

—

2. 魔法の杖:SqlBuilderクラスを設計する

まずは、面倒な文字列連結をすべて引き受けてくれる「執事」のようなクラスを作成します。

クラスモジュールの作成

1. VBE(Alt + F11)を開きます。
2. 挿入メニューから「クラスモジュール」を選択。
3. プロパティウィンドウでオブジェクト名を `clsSqlBuilder` に変更します。

以下のコードをコピー&ペーストしてください。

Option Compare Database
Option Explicit

‘ — clsSqlBuilder: SQL構築を劇的に楽にするクラス —

Private mSql As String
Private mWhereCount As Integer

‘ 最初に呼び出す初期化メソッド
Public Sub Clear()
mSql = “”
mWhereCount = 0
End Sub

‘ 単純に文字列を追加する(前後にスペースを自動で挟む)
Public Sub Append(ByVal text As String)
mSql = mSql & ” ” & Trim(text) & ” ”
End Sub

‘ WHERE句をスマートに追加する
‘ 最初の1回目は WHERE を、2回目以降は AND を自動付与する
Public Sub AddCondition(ByVal condition As String)
If mWhereCount = 0 Then
mSql = mSql & ” WHERE ” & condition
Else
mSql = mSql & ” AND ” & condition
End If
mWhereCount = mWhereCount + 1
End Sub

‘ 最終的なSQLを書き出す
Public Function Build() As String
‘ 余計な空白を整理して返す
Build = Replace(Trim(mSql), ” “, ” “)
End Function

このコードの「極限の知見」ポイント

  • スペースの自動制御: `Append` メソッドが前後にスペースを入れるため、`FROMTable` のように単語がくっついてエラーになるのを防ぎます。
  • 状態の保持: `mWhereCount` を持つことで、開発者が「今は最初の条件かな? 2番目かな?」と `AND` を付けるかどうか悩む必要をなくしています。

—

3. 実戦投入:QueryDefを動的に書き換える

それでは、作成したクラスを使って、検索フォームのボタンをクリックした時にクエリを書き換えるコードを書いてみましょう。

Private Sub btnSearch_Click()
Dim sb As New clsSqlBuilder
Dim qdf As DAO.QueryDef

‘ 1. SQLの基本部分を構築
sb.Clear
sb.Append “SELECT FROM T_商品マスタ”

‘ 2. 画面の入力状況に応じて条件を「直感的」に追加
‘ 商品名の入力があれば抽出条件に加える
If Nz(Me.txtProductName, “”) <> “” Then
sb.AddCondition “商品名 LIKE ‘” & Me.txtProductName & “‘”
End If

‘ カテゴリの選択があれば抽出条件に加える
If Nz(Me.cmbCategory, “”) <> “” Then
sb.AddCondition “カテゴリID = ” & Me.cmbCategory
End If

‘ 在庫ありチェックボックスがONの場合
If Me.chkInStock = True Then
sb.AddCondition “在庫数 > 0”
End If

‘ 3. QueryDefに流し込む
On Error GoTo Err_Handler
‘ すでに作成済みのクエリ「qrySearchResult」を操作
Set qdf = CurrentDb.QueryDefs(“qrySearchResult”)
qdf.SQL = sb.Build()

‘ クエリを表示(またはサブフォームを再クエリ)
DoCmd.OpenQuery “qrySearchResult”

Set qdf = Nothing
Exit Sub

Err_Handler:
MsgBox “SQL生成エラー: ” & Err.Description, vbCritical
End Sub

—

4. なぜこの方法が「最強」なのか

この設計を導入することで、あなたは以下の3つの苦しみから解放されます。

1. 「スペース不足」エラーの消滅
`”SELECT FROM” & “Table”` が `”SELECT FROMTable”` になる悲劇はもう起こりません。
2. 「WHERE 1=1」という古いハックの卒業
よく見かける `WHERE 1=1`(常に真の条件を置いて、後は全部 `AND` で繋ぐ手法)を使わなくても、スマートに `WHERE` と `AND` を使い分けられます。
3. 可読性の劇的な向上
`If` 文の中が「条件そのもの」だけに集中しているため、後から仕様変更(「やっぱり価格の範囲指定も追加して」など)があっても、数行足すだけで完了します。

—

5. 初学者が陥りやすい落とし穴とアドバイス

最後に、この手法を使う上での「先輩からのアドバイス」です。

  • データ型に注意!:

SQLを組み立てる際、数値型なら `ID = 1` で良いですが、文字列型なら `Name = ‘田中’` のようにシングルクォーテーションが必要です。日付型なら `#2023/10/01#` です。これだけは、`AddCondition` に渡す文字列の中で意識してください。

  • QueryDefの永続性:

`qdf.SQL = …` と書くと、Accessの中に保存されているクエリ定義そのものが書き換わります。これは非常に強力ですが、複数のユーザーが同時に同じクエリを書き換えると競合します。分割データベース(フロントエンドを各PCに配布)にする運用を心がけましょう。

まとめ

Access VBAの世界は、ただ「動けばいい」コードを書く段階から、「意図が伝わる美しい構造」を作る段階へ進むと、一気に楽しくなります。

今回紹介した `SqlBuilder` クラスは、その第一歩です。複雑なパズルを解くような文字列結合はやめて、論理を組み立てるプログラミングを楽しみましょう。これができれば、あなたのAccess VBAの基本はもう完璧と言っても過言ではありません。

次は、このクラスに「パラメーターのバインド機能」を追加する応用編でお会いしましょう。ハッピーコーディング!

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