目的、背景など
現職場ではAccessをメインにデータの集計を行っています。
最近AWS上にシステムを構築し、RDSを使うことになりました。なのでAccessにてODBC接続してデータを取り扱う機会が増えました。この職場ではAccessによるVBAで構築されたレガシーな開発標準があり、ODBC接続を自動で処理するモジュールにて接続することになるのですが、そのモジュールが機能せず、ODBCエラーを吐き続けることとなりました。
当記事はその問題対処へのレポートみたいなものです。
作業環境
- データベースエンジン(※1):Aurora PostgreSQL(エンジンバージョン12.7)
- Microsoft Access2003、Microsoft Access2016
- OS:Windows10 64bit
- ODBCドライバー(※2):PostgreSQL Unicode (バージョン13.02.00.00)
※1 私の環境では踏み台サーバ経由での利用ですが、既存のナレッジにて接続ができています。
※2 Microsoft Access2003をメインに使っているため、ODBCドライバーは32bitを使用しています。
事象
できていること
- フリーソフトA5M2等によるDB参照
- 新規作成>テーブルのリンク>ODBCデータベース() からシステムDSNやファイルDSNを使ったリンクの作成
できていないこと
- TableDef オブジェクトによるODBC自動接続
ODBCエラー
「3146 ODBC--呼び出しが失敗しました。」がプログラムをどう書き直しても出てきます。TableDefの使われ方はググれば出てくるようなオーソドックスなものなのにどこが悪いのか全く分かりません。TableDefでの接続を行ったという技術記事を調べまわると、Microsoftが公開しているAttachDSNLessTableという名前で、DSNを使用しないODBC接続の方法が紹介されていました。ぱっと見、既存のモジュールと同じ要領でTableDefが使用されていたため、
AttachDSNLessTableを丸々コピペして使ってみたのですが、3146のエラーがやっぱり出てきます。
エラー対処
3146エラーの対処をどうググっても、記事ごとに原因が異なっているため、これ以上の情報が必要となりました。そして英語のページも見飽きてきた時に以下のページを見つけました。
https://answers.microsoft.com/en-us/msoffice/forum/all/run-time-error-3146-odbc-call-failed/30fce3c6-0e05-463f-b115-41357c95a5ad
要は、エキスパートの方が言うに、プログラムの中にこれ入れればより詳細なエラーが見れるよって回答でした。この回答こそが問題解決への光明となりました。
Public Sub DumpErrorsCollection()
Dim e As Error
Debug.Print Time$, "Dumping " & DBEngine.Errors.Count & " error records:"
For Each e In DBEngine.Errors
Debug.Print e.number, e.Description, e.source
Next e
End Sub
早速エラー個所に仕込んでみると以下の出力を得ることができました。
16:28:43 Dumping 2 error records:
11 The specified table does not exist ODBC.TableDefs
3146 ODBC--呼び出しが失敗しました。 DAO.TableDefs
んん?「The specified table does not exist」?
テーブルが存在しない????
種明かし
まず、Accessで新規作成>テーブルのリンク>ODBCデータベース() からシステムDSNやファイルDSNを使って作成すると以下のようにテーブル名の前に「public.」という文字列がついてきます。(スキーマというんでしょうか?不慣れなもので...(-_-;) )
そしてOKでリンクを作成すると「public_テーブル名」という名前でリンクが作成されます。
私はVBAでTableDefにテーブル名を渡す際、「public_テーブル名」で渡していました。事前に手動で作成テストをしていたのでpublic付が印象に残っていたため、てっきり「public_テーブル名」で渡すものだと勘違いしていました。その後このスキーマを取り除いたテーブル名でモジュールを実行したら、問題なくリンクが作成されることを確認しました。
改めて調べ直したら、何度も閲覧した以下の記事でもちゃんとスキーマの処理を挟んでいるのが伺えます。。。。。
https://fnya.cocolog-nifty.com/blog/2015/04/access-postgres.html
(追記:2023/01/11時点で上記リンクは無効になっていました)
所感
VBAの開発に関わって2年ほど経ちますが、とても実のある体験だったと思います。不慣れなODBC接続であったこともそうですが、データベースに対する理解や用語・知識に目を向けることができました。
何よりDumpErrorsCollection()というデバッグ手段を学ぶことができたのが最大の収穫だと思っています。元記事の回答のいいねを連打してやりたいです。
どこかの技術記事のコメント欄に私と同じようにAccess、VBA、Postgreで手動ではリンク作成ができるのにTableDefで自動作成できないというコメントがあったため、決して自分だけがこの問題にはまった訳ではないと思っています。
以下のことで躓いている方がいて、検索したらこの記事を見つけて何かの手助けになってくれればと思います。
- ODBCエラーの対処・詳細分析
- TableDefを使うとODBCエラー3146が返ってくる