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

スポンサーリンク

こんにちは!いつも業務自動化やデータベース開発に励んでいる皆さん、調子はいかがですか?

Access VBAの基本を身につけ、マクロから卒業してコードを書き始めると、「もっと大量のデータを扱いたい」「社内の基幹システム(SQL Server)と連携させたい」というステップに進む瞬間がやってきます。これは開発者として、ものすごくワクワクする素晴らしい進化です。

しかし、そこで多くの人がガツンと頭をぶつける「謎のエラー」があります。

> 「エラー 3622: IDENTITY 列があるテーブルに、dbSeeChanges オプションを指定せずに、Insert、Update、Delete を行うことはできません。」

「アイデンティティ列?」「オプション?」と、頭の上に疑問符が浮かんでしまいますよね。
でも、安心してください。このエラーの理由と対策が分かれば、AccessとSQL Serverを連携させる開発の「基本」はバッチリ攻略できたと言えます。

今回は、このエラーの裏側で起きていること、そしてAccess VBAで最も安全かつ高速にクエリを実行するプロの書き方を、優しく、そして本質まで深く掘り下げて解説します。一緒に一歩、プロの領域へ踏み出しましょう!

1. なぜエラーが起きるの?原因を「図解的」に理解しよう

まずは、SQL ServerとAccessの間でどんなやり取りが行われているのか、イメージで理解してみましょう。

SQL Serverの「IDENTITY(自動連番)列」とは?

Accessのテーブルでいう「オートナンバー型」と同じものです。データを1行追加すると、システムが自動的に「1, 2, 3…」と重複しない番号を振ってくれる便利な仕組みです。

AccessとSQL Serverの「すれ違い」

あなたがAccessからSQL Serverのテーブルに対して「データを1件追加して!」と命令(INSERT)したとします。

[ Access (あなた) ] ───「このデータを追加して!」───> [ SQL Server ]
│ (自動で新しいID「105」を採番)
[ Access (あなた) ] <───「追加できたよ!」─────── [ SQL Server ] ここで、Accessはこう考えます。 「今追加したデータの自動連番、一体何番になったんだろう? 次の処理で使いたいから、今すぐ確かめなきゃ!」

しかし、SQL Serverは世界中の何百人ものユーザーが同時にデータを書き込む場所です。Accessが「何番になった?」と確認しに行く一瞬の隙に、他の誰かがデータを追加して、番号が変わってしまうかもしれません。

そこでAccessは、「データの整合性を守るために、SQL Server側で値が書き換わっていないか(競合していないか)を厳しく監視しながら処理を進めたいな」と考えます。

この「監視しながら処理してね!」という合図こそが、今回の主役である `dbSeeChanges` というオプションなのです。

もしこの合図を送らずに実行すると、Accessは「万が一、他の人とデータが衝突したら責任が取れないよ!」と怖がって、エラー(3622)を出してストライキを起こしてしまいます。

2. 魔法の言葉 `dbSeeChanges` の使い方

原因が分かれば、対策はとてもシンプルです。Access VBAでSQL文を実行する際に、「ちゃんと監視しているから大丈夫だよ」と教えてあげるだけです。

まずは、最も基本となる正しいコードの書き方を見てみましょう。

安全にSQLを実行する標準パターン

Sub UpdateSqlServerTable()
‘ 1. データベースオブジェクトを扱う変数を宣言する
Dim db As DAO.Database
Dim sql As String

‘ 2. 現在のデータベースへの参照を代入する(※ここが超重要!)
Set db = CurrentDb

‘ 3. 実行したいSQL文を組み立てる
‘ (例:社員テーブルに新しいメンバーを追加する)
sql = “INSERT INTO T_Employee (EmpName, Department) VALUES (‘サトウ’, ‘開発部’);”

On Error GoTo ErrorHandler

‘ 4. dbSeeChanges オプションを指定してSQLを実行する
db.Execute sql, dbFailOnError + dbSeeChanges

MsgBox “データの追加が成功しました!”, vbInformation, “成功”

ExitHandler:
‘ 5. 後片付け(オブジェクトの参照を解放してメモリをきれいに保つ)
Set db = Nothing
Exit Sub

ErrorHandler:
‘ エラーが発生した場合は、メッセージを表示して安全に終了する
MsgBox “エラーが発生しました。” & vbCrLf & _
“エラー番号: ” & Err.Number & vbCrLf & _
“エラー内容: ” & Err.Description, vbCritical, “エラー発生”
Resume ExitHandler
End Sub

コードの解説:ここがプロのこだわり!

① `dbFailOnError + dbSeeChanges` の合わせ技

`db.Execute` の後ろに書かれている `dbFailOnError + dbSeeChanges` に注目してください。

  • `dbFailOnError`: 「もし途中でエラーが起きたら、処理をすべてキャンセル(ロールバック)してね」という指示。これがないと、エラーが起きても無視して進んでしまいます。
  • `dbSeeChanges`: 「SQL ServerのIDENTITY列を安全に監視してね」という指示。

この2つをプラス記号(`+`)または `Or` で繋ぐことで、「安全かつ、エラーが起きたら即座に教えてくれる」という最強の実行モードになります。

② なぜ直接 `CurrentDb.Execute` と書かないの?

初心者向けの解説書では、よく以下のような書き方が紹介されています。

‘ 初心者がやりがちな「実は重い」書き方
CurrentDb.Execute sql, dbSeeChanges

動くには動くのですが、実は `CurrentDb` という言葉を呼び出すたびに、Accessは内部でデータベースの情報を丸ごと読み込み直す(インスタンスを新規作成する)という非常に重い処理を行っています。

プロの開発者は、必ず `Set db = CurrentDb` と一度変数に代入して、一つの「引き出し(オブジェクト)」を使い回します。こうすることで、動作が劇的に軽くなり、メモリの無駄遣い(メモリリーク)も防ぐことができるのです。

3. SQL Server連携で絶対に避けて通れない「もう一つの罠」

`dbSeeChanges` を設定して一安心……と思いきや、SQL ServerとAccessの連携には、もう一つだけ絶対に知っておくべき超重要なルールがあります。

それは、「リンクテーブルを作成するときは、必ず主キー(プライマリキー)を設定すること」、そしてできれば「SQL Server側に `timestamp`(rowversion)型の列を作っておくこと」です。

① 主キーがないと、データが「読み取り専用」になる

SQL ServerのテーブルをAccessに「リンクテーブル」として取り込む際、Accessから「どの列を一意の目印(主キー)にしますか?」と聞かれます。
ここで「キャンセル」を押したり、主キーがないテーブルをリンクしたりすると、Accessはそのテーブルのデータを1文字も書き換えることができなくなります(読み取り専用化)。必ず、一意になるID列(IDENTITY列など)を主キーとして指定してください。

② 競合を防ぐ守護神「timestamp(rowversion)型」

SQL Server側でテーブルを設計するとき、列の型に `timestamp`(SQL Server 2008以降では `rowversion` とも呼ばれます)という特殊な型を1つ追加しておきましょう。

— SQL Server側のテーブル作成例
CREATE TABLE T_Employee (
EmpID INT IDENTITY(1,1) PRIMARY KEY,
EmpName NVARCHAR(50),
Department NVARCHAR(50),
UpdateToken TIMESTAMP — ★これが超重要!
);

この `timestamp` 列があると、データが更新されるたびにSQL Serverが自動で一意のバイナリ値を書き換えてくれます。
Accessはこの値を見て、「あ、このデータは自分が読み込んだときから誰も書き換えていないな。安全に更新できるぞ!」と一瞬で判断できるようになります。

これがないと、Accessはすべての列の値を古いデータと比較しなければならず、動作が非常に遅くなったり、誰も書き換えていないのに「他のユーザーによって変更されました」という誤エラー(コンフリクト)が発生したりします。

4. まとめ:ここをクリアすれば、Access VBAの基本はバッチリ!

今回の学びを整理しましょう。

1. IDENTITY列(自動連番)があるSQL Serverのテーブルを操作するときは、`dbSeeChanges` オプションが絶対に必要。
2. `CurrentDb` は直接使わず、一度 `Dim db As DAO.Database` 変数に格納して使うのが、プロのパフォーマンス・チューニング。
3. クエリ実行時は `dbFailOnError + dbSeeChanges` の合わせ技で、安全性を最大化する。
4. SQL Server側には `timestamp` 型の列を用意しておくと、通信が劇的に安定・高速化する。

Access単体での開発から、SQL Serverという本格的なデータベースとの連携にステップアップするこの瞬間は、少し難しく感じるかもしれません。
でも、今回紹介したコードのパターンをテンプレートとして指針にしていけば、エラーに怯える必要はまったくありません。

このハードルを越えたとき、あなたの作成するシステムは、何百人ものユーザーが同時に使っても壊れない「極めて堅牢なプロ仕様のシステム」へと進化します。

一歩一歩、楽しみながらコードを書いていきましょう。応援しています!

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