こんにちは!Access VBAの世界へようこそ。
普段、ローカルのテーブルだけで完結しているときは意識しなくても、一歩外の世界——つまりSQL Serverなどの外部データベースと連携し始めた途端、Accessは牙を剥くことがあります。
「マクロの記録」を卒業し、いよいよ本格的な業務システムを作ろうとした矢先、こんなエラーに出会ったことはありませんか?
> 「実行時エラー ‘3146’: ODBC–呼び出しが失敗しました。」
このエラーは非常に不親切です。何が悪いのかを教えてくれません。しかし、その正体の多くは、今回解説する「dbSeeChanges」というオプションの欠如にあります。
今日は、Access VBAを極める上で避けては通れない、DAOとSQL Server連携の「深い部分」を、優しく紐解いていきましょう。ここを乗り越えれば、あなたのVBAスキルは「初心者」から「実戦エンジニア」へと一気に昇華しますよ。
—
1. なぜ「dbSeeChanges」が必要なのか?
結論から言いましょう。SQL Serverのテーブルに「ID列(Identity型:自動採番)」がある場合、DAOでそのテーブルを操作(追加・更新)するには、必ず「このフラグ」を立てる必要があります。
仕組みを覗いてみよう
Accessの標準(DAO)は、もともと自分の手元(ローカル)にあるテーブルを管理するために設計されました。しかし、SQL Serverと連携すると、データの主導権はサーバー側に移ります。
1. VBA側: 「新しいレコードを追加して!」と命令を出す。
2. SQL Server側: 「了解。自動でID『101』を振っておいたよ」と処理する。
3. VBA側: 「えっ、勝手にIDが決まったの? 今のレコード、僕が持ってるデータと中身が変わっちゃったじゃないか!」
このとき、DAOが「サーバー側で勝手に値が変わる(自動採番される)のをちゃんと見張っておけよ」という設定になっていないと、混乱してエラーを吐くのです。その「見張っておけよ」という合図こそが、`dbSeeChanges`なのです。
—
2. DAOとADO、どっちを使うべき?
ここで少し、アーキテクチャの全体像をお話しします。Accessから外部DBに接続する方法は主に2つあります。
- DAO (Data Access Objects): Accessの「母国語」。Accessのフォームやレポートと最も相性が良く、高速です。
- ADO (ActiveX Data Objects): 「共通語」。SQL ServerやOracleなど、Access以外との連携を主眼に置いた汎用的な規格です。
「SQL Serverを使うならADOの方がいいのでは?」と思うかもしれません。しかし、Accessのリンクテーブルを操作する場合、実はDAOの方が圧倒的に書きやすく、パフォーマンスが良いケースが多いのです。
だからこそ、DAOでSQL Serverを使いこなすための「作法(dbSeeChanges)」を知っておくことが、プロへの近道になります。
—
3. 【実践】エラーを回避するコードの書き方
それでは、実際にSQL Serverのリンクテーブルにデータを追加する、正解のコードを見てみましょう。
失敗しないための黄金律
`OpenRecordset` を呼び出す際、第2引数に `dbOpenDynaset`、第3引数に `dbSeeChanges` を指定するのが鉄則です。
Sub AddNewRecordToSQLServer()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim strTableName As String
‘ 操作したいSQL Serverのリンクテーブル名
strTableName = “T_OrderMain”
Set db = CurrentDb
On Error GoTo ErrorHandler
‘ — ここが重要! —
‘ 第2引数:dbOpenDynaset(動的セットとして開く)
‘ 第3引数:dbSeeChanges(Identity列の変更を監視する)
‘ ———————
Set rs = db.OpenRecordset(strTableName, dbOpenDynaset, dbSeeChanges)
With rs
.AddNew
‘ ID列はSQL Serverが自動で振るので、それ以外の項目を入力
.Fields(“OrderDate”).Value = Date
.Fields(“CustomerName”).Value = “株式会社サンプル”
.Update ‘ ここでdbSeeChangesがないとエラーになる!
‘ 更新直後の自動採番されたIDを確認することもできます
.Bookmark = .LastModified
Debug.Print “発行された新しいIDは: ” & .Fields(“ID”).Value
.Close
End With
MsgBox “無事にレコードが追加されました!”, vbInformation
Exit_Handler:
‘ オブジェクトの解放(メモリ管理の基本ですね)
If Not rs Is Nothing Then Set rs = Nothing
Set db = Nothing
Exit Sub
ErrorHandler:
MsgBox “エラー番号: ” & Err.Number & vbCrLf & _
“エラー内容: ” & Err.Description, vbCritical, “接続エラー”
Resume Exit_Handler
End Sub
コードのポイント解説
- `dbOpenDynaset`: SQL Serverなどの外部テーブルを操作する場合、この「ダイナセット(動的な参照)」形式で開くのが基本です。
- `.Bookmark = .LastModified`: `Update`した直後に、今追加したばかりのレコードにカーソルを戻すテクニックです。これで、SQL Serverが自動で振ったIDをすぐに取得できます。
—
4. トランザクション処理という「プロの守り」
複数のテーブルを同時に更新する場合(例えば「注文ヘッダー」と「注文明細」)、片方だけ成功してもう片方が失敗すると、データの整合性が壊れてしまいます。
そんな時は、トランザクションを使いましょう。
Sub TransactionExample()
Dim ws As DAO.Workspace
Dim db As DAO.Database
‘ 既定のワークスペースを取得
Set ws = DBEngine.Workspaces(0)
Set db = CurrentDb
On Error GoTo RollbackHandler
‘ トランザクション開始!
ws.BeginTrans
‘ ここで複数の更新処理を行う
‘ 必ず dbSeeChanges を忘れないように!
db.Execute “INSERT INTO T_Log (LogMsg) VALUES (‘処理開始’)”, dbSeeChanges
‘ … 他の処理 …
‘ すべて成功したら確定
ws.CommitTrans
MsgBox “すべての処理が正常に完了しました。”
Exit Sub
RollbackHandler:
‘ エラーが起きたら、すべて「なかったこと」にする
ws.Rollback
MsgBox “エラーが発生したため、処理を取り消しました。”, vbCritical
End Sub
—
5. まとめ:罠を回避して「信頼されるシステム」へ
Access VBAからSQL Serverへステップアップする際、多くの人が「リンクテーブルにしただけで動かなくなった」と挫折します。しかし、その原因の多くは、今回学んだ「Identity列とdbSeeChangesの関係」を知っているかどうかにかかっています。
- SQL ServerのIdentity列があるなら、`dbSeeChanges`は必須。
- DAOはAccessの最強の武器。正しく使えば高速で安定する。
- エラーが出たら「ODBC呼び出し失敗」の裏に隠れたこのオプションを疑う。
この知識を装備したあなたは、もう「ただのマクロ使い」ではありません。Accessの限界を突破し、堅牢な業務システムを構築するエンジニアへの第一歩を踏み出しました。
「ここをクリアすれば、Access VBAの基本はバッチリですよ」。
自信を持って、次のコードを書いてみてくださいね!応援しています。
