【入門編】【上級】CurrentDb.Executeの「dbSeeChanges」オプション:SQL Server連携時の排他制御エラーを解決する – Access VBA解析バイブル

スポンサーリンク

こんにちは!Access VBAの世界へようこそ。
ここまで足を踏み入れたあなたなら、きっと「もっとスマートに、もっとエラーのないシステムを作りたい」という熱い探求心を持っていることでしょう。

今回は、Accessをフロントエンド、SQL Serverをバックエンド(データの置き場所)にした、いわゆる「A/S構成(Access × SQL Server)」のシステム開発において、避けて通れない非常に重要なテーマを取り上げます。

その名も「`CurrentDb.Execute` の `dbSeeChanges` オプション」です。

「なんだか難しそうな名前だな…」と思いましたか?大丈夫です。私と一緒に、一つひとつパズルを解くように紐解いていけば、あっという間にマスターできますよ。ここをクリアすれば、あなたもワンランク上の「実務で通用するエンジニア」の仲間入りです。さあ、一緒に扉を開けましょう!

1. 現場で突然襲いかかる「他のユーザーが変更しました」の恐怖

Accessを使い慣れてくると、データを追加・更新するときに `CurrentDb.Execute` という強力なメソッドを使うようになりますよね。

‘ よくあるデータの更新コード
CurrentDb.Execute “UPDATE T_受注 SET ステータス = ‘完了’ WHERE 受注ID = 100”, dbFailOnError

このコード、テーブルがAccessの中(ローカル)にあるうちは何の問題もなく爆速で動きます。
しかし、プロジェクトが大きくなり、「バックエンドのデータをSQL Serverに移行しよう!」となった途端、現場でこんな悪夢のようなエラーが発生します。

> 実行時エラー ‘3197’:
> 「データの変更内容がほかのユーザーによって変更されたため、データは保存されませんでした。」

「えっ? 今、誰も他の操作なんてしてないのに!?」
そう叫びたくなる瞬間です。実はこれ、Accessのデータベースエンジン(Jet / ACE)と、SQL Serverの間に横たわる「セキュリティと排他制御のルール」が原因で引き起こされる、プログラミング初学者が必ずと言っていいほどハマる大きな罠なのです。

2. なぜこのエラーが起きるのか?(背後にある仕組み)

なぜ、誰も触っていないのに「他のユーザーが変更した」と言われてしまうのでしょうか?

これを理解するために、少しだけバックグラウンドの話をさせてください。
Accessの標準機能は、データの変更を検知するために「タイムスタンプ(あるいはそれに準ずる行バージョン)」のような仕組みを使っています。

ローカルのAccessテーブルであれば、エンジン同士が阿吽の呼吸でデータを管理できるため問題ありません。しかし、バックエンドがSQL Serverに変わると話は別です。
SQL Server側には、データが外部から変更された可能性を厳格に検知する機能(オプティミスティック同時実行制御)が働きます。

この時、Access側から「このデータを書き換えて!」と命令した際、「本当にこの瞬間、他の誰かがこのデータをいじっていないか、ちゃんと監視して確認しながら書き換えな定型手続き(dbSeeChanges)」を指示しないと、SQL Server側が「セキュリティ上、安全確認が取れない!」とパニックを起こしてエラーを吐いてしまうのです。

つまり、SQL Serverと連携する世界では、Accessは「ねえ、ちゃんと周りを確認しながら更新してよね!」と念を押してあげる必要があります。その念押しこそが、今回主役の `dbSeeChanges` なのです。

3. 救世主:`dbSeeChanges` を使った正しい書き方

百聞は一見に如かず。実際のコードを見てみましょう。
SQL Serverと連携しているテーブルに対して `UPDATE` や `INSERT`、`DELETE` を行うときは、必ず第二引数に `dbSeeChanges` を指定します。

【実用コード例】SQL Server連携に対応した安全な更新処理

Sub UpdateOrderStatusWithSQLServer()
Dim strSQL As String
On Error GoTo ErrorHandler

‘ 更新用SQL文の組み立て
strSQL = “UPDATE T_受注 ” & _
“SET ステータス = ‘出荷済み’, 更新日時 = Now() ” & _
“WHERE 受注ID = 1005;”

‘ 【超重要】dbSeeChanges を指定して実行する!
‘ 複数のオプションを指定する場合は 「+」 で繋ぎます(例: dbFailOnError + dbSeeChanges)
CurrentDb.Execute strSQL, dbFailOnError + dbSeeChanges

MsgBox “データの更新が正常に完了しました。”, vbInformation, “成功”
Exit Sub

ErrorHandler:
‘ エラーハンドリング(現場のプロ必須の作法です)
MsgBox “エラーが発生しました。” & vbCrLf & _
“エラー番号: ” & Err.Number & vbCrLf & _
“エラー内容: ” & Err.Description, vbCritical, “システムエラー”
End Sub

コードのここがポイント!

1. `dbFailOnError`
SQLの実行中に途中でエラーが起きた場合、それまでの変更をすべてロールバック(なかったことに)して整合性を守るための必須オプションです。
2. `dbSeeChanges`
今回の一番のテーマです。「SQL Server等の外部データベースで変更の競合が発生した際、それを正しく検知・制御する」ためのオプションです。
3. 足し算(`+`)で組み合わせる
VBAでは、複数の定数を足し算することで、同時に複数の挙動をエンジンに指示することができます。実務では `dbFailOnError + dbSeeChanges` はセットで覚えるべき黄金の組み合わせです。

4. さらに知っておくべきプロの知見:オートナンバー(IDENTITY)の罠

`dbSeeChanges` が必要なのは、実は `UPDATE` だけではありません。
SQL Serverのテーブルで、自動採番フィールド(`IDENTITY`列)を持つテーブルに対してデータを `INSERT`(追加)し、「その直後に、今追加したレコードのID(採番された番号)を知りたい!」という場面でも、このオプションが不可欠になります。

もし `dbSeeChanges` を付けずに `INSERT` を行うと、SQL Server側が「新しく何番のIDが振られたか」をAccess側にうまく返せず、予期せぬ不具合を生む原因になります。

もしSQL Server環境で「データを追加して、そのIDを取得する」ような複雑な処理を書く場合は、`CurrentDb.Execute` よりも、より柔軟にトランザクションとレコードセットを制御できる DAO の `Recordset` オブジェクトの利用を検討するのが、シニアエンジニアとしてのスマートな選択肢になります。

5. おわりに:ここをクリアすれば、もう怖くない!

お疲れ様でした!今回は、Access VBAとSQL Serverを連携させる際の最大の関所の一つである `dbSeeChanges` について解説しました。

  • ローカル環境の常識をそのままSQL Serverに持ち込むと痛い目を見る。
  • SQL Server連携の `Execute` には、`dbSeeChanges` を添えるのがプロの作法。
  • `dbFailOnError + dbSeeChanges` は、実務で戦うための最強のコンビ。

この知識さえあれば、将来あなたがより大規模なシステム開発や、クラウドデータベースとの連携に挑むことになっても、エラーに慌てず冷静に対処できるはずです。

「動かない」には必ず理由があり、それを知ることであなたのスキルは確実に一段階上がります。
一歩ずつ、確実に、頼もしいエンジニアへの階段を登っていきましょう。あなたのAccess VBAライフを、私はこれからも応援しています!

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