【入門編】複雑な抽出条件を動的に構築する「クエリビルダークラス」の設計 – Access VBA解析バイブル

スポンサーリンク

こんにちは!Access VBAでの開発、日々の試行錯誤お疲れ様です。

「条件によって検索する項目が変わる」「チェックボックスのオンオフで、WHERE句の組み合わせが何通りにも膨れ上がる……」
そんな複雑な抽出条件に直面して、コードの中で大量の `If` 文を書き殴り、カオスと化したSQL文に頭を抱えた経験はありませんか?

今回は、そんな地獄のような条件分岐からあなたを解放し、スマートで拡張性の高いコードを書くための「クエリビルダークラス」の設計手法を伝授します。

ここをクリアすれば、あなたのAccess VBAのスキルは間違いなく一段上のステージに上がります。一緒に本質をマスターしていきましょう!

—

なぜ、動的な条件分岐はコードを汚すのか?

例えば、顧客管理システムで「氏名」「都道府県」「登録日(期間)」の3つの条件を自由に組み合わせて検索したいとします。

素朴に書くと、こうなりますよね。

‘ ──【やってはいけないアンチパターンの例】──
Dim sql As String
sql = “SELECT FROM T_Customers WHERE 1=1”

If Me.txtBame <> “” Then
sql = sql & ” AND 氏名 LIKE ‘%” & Me.txtName & “%'”
End If
If Me.cmbPref <> “” Then
sql = sql & ” AND 都道府県 = ‘” & Me.cmbPref & “‘”
End If
If Me.txtDateFrom <> “” Then
sql = sql & ” AND 登録日 >= #” & Me.txtDateFrom & “#”
End If
‘ ……これに「~まで」が加わると、さらにIfの嵐!

この書き方、実は実務では「保守性の爆弾」と呼ばれます。

  • 条件が増えるたびに `If` の組み合わせが爆発する
  • シングルクォーテーションや日付のシャープ(`#`)の付け忘れによる構文エラーが頻発する
  • SQLインジェクション(今回は簡易的な例ですが)の隙が生まれる

これを美しく、安全に、そしてパーツごとに部品化して組み立てるのが「クエリビルダークラス」という設計思想です。

—

クエリビルダークラスの全体像

オブジェクト指向の考え方(と言っても難しくありません!)を使い、「条件を溜め込む箱」をクラスモジュールとして作ります。

イメージとしては、以下のような流れです。

1. クラスのインスタンスを作る(ビルダさんを呼ぶ)
2. 条件を追加する(「氏名が〇〇」「都道府県が〇〇」と伝言する)
3. SQLを生成してもらう(「よし、綺麗に結合したSQLをちょうだい!」)

それでは、具体的なコードを見ていきましょう。

—

実装ステップ1:クラスモジュールを作る

まずは、VBAのVBE画面で「挿入」>「クラス モジュール」を選択し、プロパティウィンドウで名前を `QueryBuilder` に変更してください。

以下のコードを丸ごと貼り付けます。

‘ =================================ع
‘ クラス名:QueryBuilder
‘ 概要:WHERE句の条件を安全かつ動的に組み立てるクラス
‘ =================================
Option Explicit

Private m_BaseSql As String
Private m_Conditions As Collection

‘ 初期化処理(コンストラクタの代わり)文書作成時にベースとなるSELECT句を渡す
Public Sub Init(ByVal baseSql As String)
m_BaseSql = baseSql
Set m_Conditions = New Collection
End Sub

‘ 条件を追加するメソッド
‘ field: 項目名 (例: “都道府県”)
‘ op: 演算子 (例: “=”, “LIKE”, “>=”)
‘ value: 値 (例: “東京都”)
Public Sub AddCondition(ByVal field As String, ByVal op As String, ByVal value As Variant)
‘ 値がNullや空文字の場合は、条件自体を追加しない(これが超重要!)
If IsNull(value) Then Exit Sub
If Trim(CStr(value)) = “” Then Exit Sub
ペ
‘ 条件を格納する構造体(自作クラスか配列でも良いが、今回はシンプルに文字列で保持)
Dim condStr As String

‘ データ型に応じたエスケープ処理や囲み文字の調整
Select Case UCase(Trim(op))
Case “LIKE”
‘ あいまい検索の場合
condStr = field & ” LIKE ‘%” & EscSql(CStr(value)) & “%'”
Case “>=”, “<=", ">“, “<", "=" ' 数値や日付、完全一致の場合(簡易的に数値・日付の判定を入れるとより堅牢) If IsDate(value) Then condStr = field & " " & op & " #" & Format(value, "yyyy/mm/dd hh:nn:ss") & "#" ElseIf IsNumeric(value) Then condStr = field & " " & op & " " & value Else condStr = field & " " & op & " '" & EscSql(CStr(value)) & "'" End If Case Else ' その他カスタム演算子 condStr = field & " " & op & " '" & EscSql(CStr(value)) & "'" End Select m_Conditions.Add condStr End Sub ' 完成したSQLをビルド(出力)するメソッド Public Function Build() As String Dim sql As String sql = m_BaseSql If m_Conditions.Count > 0 Then
‘ ベースSQLにすでにWHERE句が含まれているか簡易チェック
If InStr(UCase(m_BaseSql), “WHERE”) = 0 Then
sql = sql & ” WHERE ”
Else
sql = sql & ” AND ”
End If

‘ 溜まった条件を AND で結合する
Dim i As Long
Dim tmpArr() As String
ReDim tmpArr(1 To m_Conditions.Count)

For i = 1 To m_Conditions.Count
tmpArr(i) = m_Conditions(i)
Next i

sql = sql & Join(tmpArr, ” AND “)
End If

Build = sql
End Function

‘ 簡易的なSQLインジェクション対策(シングルクォーテーションのエスケープ)
Private Function EscSql(ByVal val As String) As EscSql
EscSql = Replace(val, “‘”, “””)
End Function

—

実装ステップ2:フォームや標準モジュールから呼び出す

先ほど作ったクラスを、実際の画面(フォーム)の検索ボタンなどで使ってみましょう。驚くほどすっきりと書けます。

‘ =================================
‘ 検索ボタンがクリックされた時の処理の例
‘ =================================
Private Sub 検索実行ボタン_Click()
Dim qb As QueryBuilder
Set qb = New QueryBuilder

‘ 1. ベースとなるSQLをセットして初期化
qb.Init “SELECT FROM T_Customers”

‘ 2. 画面の入力値から、存在する条件だけを次々に追加する
‘ (もし空欄なら、クラス側で自動的に無視してくれます!)
qb.AddCondition “氏名”, “LIKE”, Me.txtSearchName.Value
qb.AddCondition “都道府県”, “=”, Me.cmbSearchPref.Value
qb.AddCondition “登録日”, “>=”, Me.txtSearchDateFrom.Value

‘ 3. 最終的なSQLを構築して取得
Dim finalSql As String
finalSql = qb.Build()

‘ デバッグウィンドウで確認
Debug.Print finalSql

‘ 4. フォームやレポートのレコードソースに設定する
Me.RecordSource = finalSql
Me.Requery

‘ クリーンアップ
Set qb = Nothing
End Sub

—

ここがエンジニアの知見!陥りやすい罠と極意

1. 「空文字」と「Null」の魔力

Accessのフォーム上でテキストボックスが空のとき、それは `””`(長さ0の文字列)であったり、データベースのフィールド由来だと `Null` であったりします。
今回のクラス内では `If IsNull(value) Then Exit Sub` と `If Trim(CStr(value)) = “” Then Exit Sub` を設けているため、「ユーザーが何も入力しなかった項目は、自動的にWHERE句から除外される」という最高にエレガントな挙動を実現しています。

2. データ型に応じた囲み文字(`#` と `’`)の自動化

VBAでありがちなのが、「日付の ` # ` を忘れて構文エラー」「文字列の ` ‘ ` を忘れて構文エラー」という凡ミスです。
クラス内の `Select Case` で、値が日付なら `#`で囲み、数値ならそのまま、文字列なら `’`で囲むという分岐をカプセル化(隠蔽)しているため、呼び出し側はデータ型の違いを意識せずに `AddCondition` を呼ぶだけで良くなります。これがプロの設計です。

—

おわりに

いかがでしたでしょうか?
「クエリビルダークラス」という名前を聞くと难しそうに感じるかもしれませんが、やっている本質は「条件を安全な箱にポイポイ入れて、最後にキレイに糊付けしてもらう」という非常にシンプルなものです。

このクラスを一度作っておけば、どんなに複雑な検索画面を作ることになっても、あなたのコードが汚れることは二度とありません。

ここをクリアすれば、Access VBAの基本はもうバッチリ、中級者への扉は開いています。
ぜひ、あなたの開発現場にもこの設計を取り入れて、快適なVBAライフを送ってくださいね!

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