【実務・中級編】CurrentDb.Executeの「dbSeeChanges」オプションが必要なケースとSQL Server連携の注意点 – Access VBA解析バイブル

スポンサーリンク

Access×SQL Server連携の暗部:なぜ`dbSeeChanges`を怠るシステムは崩壊するのか

Accessをフロントエンド、SQL Serverをバックエンドに据えた「ADP(Access Data Project)の遺産」を彷彿とさせる構成、あるいはODBCによるリンクテーブル構成。これらは現代の業務システムにおける王道だが、多くの開発者が「なぜか時々動かなくなる」という不可解なエラーに頭を抱える。

その原因の9割は、`CurrentDb.Execute`の背後にある「楽観的な想定」だ。今日は、AccessからSQL Serverを叩く際に避けて通れない「`dbSeeChanges`」という魔術の正体と、プロフェッショナルが書くべき「死なないコード」について伝授する。

1. なぜ「dbSeeChanges」が必要なのか?

SQL Serverには「レプリケーション」という概念が存在する。Accessのリンクテーブル越しにデータを更新する際、SQL Server側で「この行は今、誰かに書き換えられたのではないか?」という競合チェックが走ることがある。

特に「オートナンバー型(SQL ServerのIDENTITY)」「ユニークインデックス」が絡むテーブルにおいて、Accessのデフォルトの挙動ではこの競合検知に失敗し、以下のエラーが吐き出される。

> 「実行時エラー 3622: レプリケーション ID または IDENTITY 列を含むテーブルを更新するには、dbSeeChanges オプションを使用する必要があります。」

これは単なるエラーではない。「君のコードはマルチユーザー環境の整合性を保証できていない」というSQL Serverからの警告だ。これを無視して`DoCmd.RunSQL`(警告ダイアログが出る上に遅い)で逃げるのは、プロとしては論外である。

2. プロダクションコード:失敗しないExecuteの書き方

現場で保守に追われないためには、エラーハンドリングを標準搭載し、かつ`dbSeeChanges`を明示した設計が必須となる。以下のコードをテンプレートとしてストックしてほしい。

‘ ==============================================================================
‘ 目的: SQL Serverへの安全なデータ更新実行
‘ 引数: strSQL -> 実行するSQL文
‘ 備考: dbSeeChangesを忘れると、IDENTITY列のあるテーブルでエラーとなる
‘ ==============================================================================
Public Sub SafeExecuteSQL(ByVal strSQL As String)
Dim db As DAO.Database

‘ 常にCurrentDbを直接参照せず、オブジェクト変数に格納する(メモリ効率の最適化)
Set db = CurrentDb

On Error GoTo ErrorHandler

‘ dbSeeChangesを付与して実行。
‘ dbFailOnErrorを併用することで、トランザクションの不整合も防ぐ
db.Execute strSQL, dbSeeChanges + dbFailOnError

Exit Sub

ErrorHandler:
‘ ここでログ出力やエラー通知を行う
MsgBox “データベース更新エラー: ” & Err.Description, vbCritical
‘ 必要に応じてRollback処理を記述する
End Sub

なぜこの書き方が「正解」なのか?

1. `dbFailOnError`の活用: `db.Execute`はデフォルトではSQLにエラーがあっても黙って無視する仕様がある。これを併用することで、失敗時には即座にエラーをキャッチし、不正なデータがDBに書き込まれるのを防ぐ。
2. `CurrentDb`のキャッシュ: `CurrentDb`を何度も呼ぶのは、毎回新しいDB接続オブジェクトを生成するコストが発生する。変数に一度格納することで、パフォーマンスとメモリの断片化を抑制している。

3. SQL Server連携の「3つの鉄則」

現場でトラブルを起こさないために、以下の規律をチームの標準としてほしい。

① リンクテーブルの「主キー」を疑え

AccessからSQL Serverのテーブルをリンクする際、主キーが正しく認識されていないと更新が不可になる。リンクテーブルを作成した際、Accessが主キーを特定できない場合は即座に「更新不可のレコードセット」と見なされる。必ずSQL Server側で主キーが定義されているか、リンク時にAccess側でインデックスを指定できているか確認すること。

② `DoCmd.RunSQL`は使うな

`DoCmd.RunSQL`はGUIの恩恵(確認ダイアログ)を受けるためのものだ。自動化プロセスにおいて、ユーザーに「はい/いいえ」を尋ねる設計はバグの温床となる。常に`DAO.Database.Execute`メソッドを使用せよ。

③ トランザクションを意識せよ

複数のSQLを連続で投げる場合、`db.BeginTrans`と`db.CommitTrans`で囲むのが基本だ。もし途中でエラーが発生したなら、`db.Rollback`で巻き戻す。`dbSeeChanges`を正しく使うことは、このトランザクションの整合性を担保する第一歩である。

最後に:エンジニアとしての矜持

「とりあえず動けばいい」というコードは、数ヶ月後の自分への負債となる。特にAccessとSQL Serverの境界線で発生するエラーは、再現性が低く、デバッグに時間を浪費しやすい。

`dbSeeChanges`という小さな定数を書くことは、単なるオプションの指定ではない。「私はデータベースの整合性に責任を持つエンジニアである」という宣言そのものだ。

君たちがこれから作るツールが、エラーというノイズに悩まされることなく、ビジネスのスピードを加速させる武器になることを期待している。次回の現場でも、このコードを武器に戦ってくれ。

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