【テクニカル・上級編】動的SQLにおける「NULL値」の扱いとIS NULL判定の罠 – Access VBA解析バイブル

スポンサーリンク

【Access VBA】QueryDefの深淵:動的SQLにおけるNULLの呪縛と「解」

Access開発において、`QueryDef`を使いこなせているか否かで、そのエンジニアの格が決まる。

多くの者は`DoCmd.RunSQL`や、野良の文字列連結でSQLを生成しては、実行時に「型不一致」や「予期せぬNULLの脱落」で夜を明かす。だが、真にシステムを支配する者は、「SQL生成のライフサイクル」と「Jet/ACEエンジンの評価ロジック」を完璧に制御下に置いている。

今回は、動的SQLにおいて誰もが一度は地獄を見る「NULLの扱い」に焦点を当て、堅牢なアーキテクチャへの昇華を目指す。

—

1. なぜ「NULL」は動的SQLを破壊するのか

SQLにおける`= NULL`は常に`Unknown`を返し、フィルタリングから除外される。これは基礎中の基礎だ。しかし、動的SQLを生成するロジックにおいて、パラメータがNULLであるか否かを、文字列連結の段階で「SQL構文としてどう解釈させるか」を設計していないコードが多すぎる。

例えば、`WHERE field = ` & varValue と書いたとき、`varValue`がNULLならSQLは崩壊する。これを防ぐために、我々は動的なバリデーションと、SQL構文の切り替えを実装せねばならない。

—

2. 実装の極致:QueryDefとパラメータ管理の定石

オブジェクトの生成と破棄を疎かにする者は、メモリリークという名の「時限爆弾」を抱えていることになる。`QueryDef`を生成したら、必ず明示的に破棄せよ。そして、動的SQLの構築には、文字列連結ではなく`Parameters`コレクションを介した「型安全なパラメータ化」を推奨する。

堅牢な動的SQL実行のテンプレート

Public Sub ExecuteDynamicQuery(ByVal targetParam As Variant)
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim strSQL As String

Set db = CurrentDb

‘ 1. SQLの雛形を動的に決定する(IS NULL判定の分岐)
If IsNull(targetParam) Then
strSQL = “SELECT FROM T_Master WHERE TargetField IS NULL”
Else
strSQL = “SELECT FROM T_Master WHERE TargetField = [prmValue]”
End If

‘ 2. オブジェクト生成(既存の名前があれば削除して再作成)
On Error Resume Next
db.QueryDefs.Delete “tmp_Query”
On Error GoTo 0

Set qdf = db.CreateQueryDef(“tmp_Query”, strSQL)

‘ 3. パラメータの注入(NULLでない場合のみ)
If Not IsNull(targetParam) Then
qdf.Parameters(“prmValue”).Value = targetParam
End If

‘ 4. 実行またはレコードセット取得
Dim rs As DAO.Recordset
Set rs = qdf.OpenRecordset(dbOpenSnapshot)

‘ … ここで処理 …

‘ 5. 明示的なクリーンアップ(極めて重要)
rs.Close
Set rs = Nothing
qdf.Close
Set qdf = Nothing
Set db = Nothing
End Sub

—

3. レガシーシステムにおけるメモリ最適化の真髄

Access VBAのガベージコレクションを信用してはならない。特に、大規模なレコードセットを扱う際、`Recordset`や`QueryDef`の解放忘れは、システムの応答速度を確実に劣化させる。

  • Set Nothingの徹底: スコープを抜ける前に、必ず参照を解放する。これは単なるマナーではなく、Jetエンジン(ACE)のロックファイルを適切に閉じるための「儀式」である。
  • 名前付きQueryDefの再利用: 頻繁に実行するクエリであれば、`CreateQueryDef`を繰り返すのではなく、永続的な`QueryDef`の`SQL`プロパティを書き換える手法を取るべきだ。ただし、マルチユーザー環境での競合には細心の注意が必要となる。

—

4. 伝説のエンジニアに求められる「もう一段上の視点」

システム間連携において、外部APIや他DBとデータを同期する際、このNULL判定ロジックはより複雑化する。

  • NULLと空文字の境界: VBAの`Null`と、データベース上の`””`(空文字)は別物だ。`Nz()`関数で安易に変換せず、ビジネスロジック上で「未設定」と「空」を明確に区別してSQLへ渡すことが、バグを未然に防ぐ唯一の道である。
  • Windows APIの介入: 極限のチューニングを求めるなら、`GetTickCount`等を用いてクエリの実行時間を計測し、ログ出力する機能をラップしておくべきだ。ボトルネックは常に「クエリの実行計画」にある。

結びとして

コードは「動けばいい」ものではない。「将来、誰がメンテナンスしてもバグを生ませない構造」こそが、シニアエンジニアが担保すべき品質だ。`QueryDef`を操り、NULLという不確定要素を飼い慣らすこと。それが、Accessというレガシーの海を渡り切るための、唯一の技術的回答である。

さあ、今すぐ自身のコードを見直せ。そこにはまだ、君の手で最適化されるべき「未解決のNULL」が眠っているはずだ。

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