Accessにおいて、データ検索フォームをVBAで作成しています。
いままで32bit版のAccessでは問題なかったのですが、そろそろ64bit版に対応させたいと考えています。
帳票フォームに検索の結果をリストさせるために、フォーム上のテキストボックスに対して以下のように記述しています。
Set Me.Recordset = rs
Me.Data1.ControlSource = rs![data1].Name
Me.Data2.ControlSource = rs![data2].Name
データクリア時に、これらテキストボックスのControlSource = "" としています。
32bit版のAccessでは問題なく動作しているものの、64bit版だとテキストボックスに#Name? が表示されます。
何かしら32bit版と64bit版のデータ形式の違いに対するおまじないが必要なのかなぁと想像しているのですが、うまく解決できず悶々としています。
お力添えいただけますと幸いです。
特に根拠は無いですけど
個人的には、以下の2つを試してみます。
【 1 】
Me.Data1.ControlSource = rs![data1].Name
Me.Data2.ControlSource = rs![data2].Name
の記述を
Data1.ControlSource = rs![data1].Name
Data2.ControlSource = rs![data2].Name
として、Me. を外してみてもエラーが出るのか
【 2 】
Set Me.Recordset = rs
の後に
Requery 系メソッドを発行してる箇所があったらコメントアウト
此方32bit版なのであれですが、『Set rs = Me.Recordset』みたいな記述をよく見ます。
32bit版の問題が起こらないコード、64bit版の問題が起きるコード、エラーメッセージの有無、もう少し詳しく出さないのでしょうか?
mayu様、りんご様
コメントありがとうございます。
mayu様
おっしゃる通り、Me.をはずしたり Me!Data1.ControlSourceとしてみたり、
はたまた Me.Data1.ControlSource = "DATA1" など指定してみたりしましたが、
結果変わらず、テキストボックスの表示が #Name? となります。
Requery系については、少々複雑なコードでしたがそのような箇所がみあたらず、
また、これら指定の直後にPauseいれて確認したのですが、この指定直後にはすでに#Name?表示でした。
この時のControlSourceに指定した rs![data1].Name の値は期待通りの文字列で"DATA1"でした。
これも文字列として .ControlSource = "rs![DATA1]" としたり "[rs]![DATA1]"としたりして試したのですが変わらずで…
rs![data1].valueには正しくデータが見えるので、rsにデータが入っていないとか間違っているという事はありません。
りんご様
32bit版では問題なく動作しているコードですが、64bit版のAccessにおいてはその表示が#Name?となっています。
エラーは発生せず、表示が#Name?となるだけなのです。
rs にはSQLを発行した結果がすでに入っており、その抽出データをリスト表示させているものです。
64bit版Accessにおいては、.ControlSourceへの指定方法が変わったのかと思い検索しましたが良い情報もみつからず、諸先輩方に同一の経験をされた方がいらっしゃれば、と思い質問させていただきました。
では、思いつく限りで あと4つほど提案してみます。
以下のいずれでもダメだった場合、ちょっとお手上げですね。
【 1 】
循環参照という可能性も無くはないと思いますから
その可能性も検証してみましょう。
Data1, Data2 というコントロール名を Recordset のカラム名とは異なる名前に変更します。
Data1 から Data_1 に変更
Data2 から Data_2 に変更
コントロールソースに値を代入する際、Recordset のカラム名を [ ] で括って
オブジェクト名であることを明記します
Me. ではなく、Forms("フォーム名").Controls("コントロール名") として
Access が誤認識する余地を完全に無くします。
※ フォーム名はご自身の環境に合わせて下さいね。
その結果、以下のようになるはずの
といった記述でも #Name? になりますか。
【 2 】
( くろさんから垣間見えるスキルからして、可能性は限りなく低いと見てはいますけど )
フォーム名やテーブルの列名といったオブジェクト名において
といった怪しい文字を使っていたら、一旦全て半角英数に変更。
【 3 】
「 ファイル 」メニューから
「 オプション 」→ 「 現在のデータベース 」と進み、
「 名前の自動修正オプション 」にあるチェック項目を全て外す
【 4 】
新規の accdb を作成し、全てのオブジェクトをインポートしてみる
>> 3
もしかして、こんなコード?
mayu様、りんご様
コメントありがとうございます。
mayu様
結果から申しますと、すべて変わらずで#Name?のままでした。
【 4 】のご提案は、Accessファイルのゴミが原因ならこれで解決!と思いまっさらな状態から簡単なものを作成しましたがダメでした…。
りんご様
方法はその通りです。rsをこの中でCloseしてしまうと、リンクデータが無くなってしまうのでCloseはしていません。
こちらの環境では、データはSQLServer上にあり、リンクテーブルからADOdbで読んでいます。
そこで、mayu様のご提案で作成した新しいaccdbがありましたので、これにローカルテーブルを作成して試したところ…
そちらは正しく表示されます!
ですので、ADO接続の際のリンクに何かあるのかもしれません。
新しく作成したaccdbのコードは以下で、このaccdbを32bitAccessで動作させると問題なく、64bitAccessではダメなのが再現できました。なんでか全くわからずです。
何かしょうもない見落としな気もするのですが…
Private Sub cmdADODB_Click()
Dim rs As New ADODB.Recordset
Dim strSQL As String
strSQL = "SELECT * FROM リンクテーブル WHERE DATA1 LIKE '%みかん%'"
rs.Open strSQL, cn, adOpenStatic, adLockOptimistic
' cn はADOBE.Connection としてSQLServerに接続しています。
Set Me.Recordset = rs
If rs.EOF = False And rs.BOF = False Then
Me.txtData1.ControlSource = rs![DATA1].Name
Me.txtData2.ControlSource = rs![DATA2].Name
End If
Set rs = Nothing
End Sub
Private Sub cmdlocal_Table_Click()
Dim rs As DAO.Recordset
Dim strSQL As String
strSQL = "SELECT * FROM test_table WHERE DATA1 LIKE '%みかん%'"
Set rs = CurrentDb.OpenRecordset(strSQL)
Set Me.Recordset = rs
Me.txtData1.ControlSource = rs![Data1].Name
Me.txtData2.ControlSource = rs![Data2].Name
Set rs = Nothing
End Sub
Private Sub cmdClear_Click()
Me.txtData1.ControlSource = ""
Me.TxtData2.ControlSource = ""
Set Me.Recordset = Nothing
End Sub
結論から申し上げると
リンクテーブルを作った時点で ADO を使う必要は無いでしょう。
Accessのオブジェクト構造とミドルウェアの選定がミスマッチという印象を受けます。
は、OLEDB 接続した SQLServer の Recordset を
ダイレクトにAccessフォームへバインドするときに有効な方法ですから
ローカルにリンクテーブルが存在する現在の構成ですと、このコードは不要です。
王道の連結フォームでAccessデータベースを運用すればいいでしょう。
これは 32bit, 64bit に関係なく問題があるでしょう。
リンクテーブルは、ローカルにあるのに
ADODB.Connection はローカルではなく、サーバーに接続しています。
また、リンクテーブルというのは 外部データベースのスキーマを
Access用に変換したテーブルですから、操作は ADO ではなく、DAO でおこないましょう。
最後に、動作がおかしくなるのは おそらく
64bitアプリにおいて、32bitアプリ用のODBCドライバを使っているからでしょう。
64bitのODBCドライバを使ってリンクテーブルを作成して下さい。
mayu様
アドバイスありがとうございます。とても助かります!
10年以上にわたり使用されていた接続の方法に問題があったとは…コードしか見ていませんでした。
複雑に絡み合った古いものに手を付けるのが面倒ではありますが、良い機会ですから見直し進めてみます。
ODBCは64bitでデータソース接続しただけで安心していました。ドライバが必要なんですね。探してみます。
とても助かりました。精進いたします!
すみません、私の勘違いがありましたので、訂正と報告です。
これはリンクテーブルではなく、SQL Server上のテーブルから読んでいました。
rsがADODBで接続されているので当然の事でした。
同じくAccess上にリンクテーブルも張られていましたが、こちらはクエリを使用するためで
試しにリンクテーブルをすべて削除しても動作変わらずでした。(リンク先が無いエラーにはなりませんでした。)
ODBCのドライバですが、[ODBC Driver 17 for SQL Server]をインストールし、ADODBの
接続に"Provider=MSOLEDBSQL";としてもダメでした。(ちなみにSQLOLEDBも試しましたが同様でした。)
また、ODBCデータソースアドミニストレータ(64ビット)において、インストールした
ODBC Driverを使ってシステムDSNを構成し、このDSNを使って接続した場合も結果同じでした。
mayu様より、リンクテーブルを使ってDAOで読めば良いとのアドバイスをいただき試したところ、
この場合は正しく動作しました!ありがとうございます!!
DAO接続では正しく動作したのでそうすればよいのですが、修正箇所が多く…またデータ量が
多いうえ多人数で使用するシステムなので出来ればADO接続の方が良いのかなと考えています。
64bitAccessへの移行はすぐに絶対対応しないといけないと言うわけでもないため、引き続き
良い解法が無いか探しています。
引き続き良いアイデアがあればアドバイスいただけますと幸いです。
以下、試行中のイケた接続とイケてない接続方法です。
ODBCドライバーをインストールしたけれど、ADO接続が上手く出来ない、という事ですが、もしかしてOLEDBドライバーも要るのかも?正直、サーバー接続までやったことがないので、間違えならごめん。
Access を SQL Server に接続する - Microsoft Support
おや。
MSOLEDBSQL プロバイダは ODBC ではなく、OLEDB ドライバーではなかったでしょうか。
Microsoft OLE DB Driver for SQL Server
あと、念の為に申し上げておきますと
ODBCドライバが関係するのは、「 リンクテーブル 」です。
ADO で SQLServer に接続しているコードにおいては
OLEDB接続のため、ODBCドライバは関係ありません。
私はクロさんと見解が少し異なります。
ADO は【 SQLServerに接続し、操作するミドルウェア 】という点においては
確かに DAO より優位であると考えています。
ですが、Access フォームに SQLServer のデータをバインドする
という状況下では、利用しないでしょう。
ADO を利用しない理由としては、Access のフォーム
つまり Me.Recordset が DAO そのものであるから、です。
( Me.Recordset が ADO でいられるのは、現在は利用できない ADP だけですね )
なので、Set Me.Recordset = rs というコードは
ADO.Recordset が DAO.Recordset に暗黙変換されて
Access のフォームにバインドされます。
動作原理はリンクテーブルと似たりよったりでしょう。
したがって、パフォーマンスをお求めの場合はリンクテーブルではなく
パススルークエリをフォームのレコードソースに指定することをお薦めします。
以下のようにコードを変更して原因を探ってみてはいかがでしょう。
りんご様、mayu様
ご指摘ありがとうございます。まだ頭の整理がキチンとついていないようです。
お恥ずかしい(/ω\)
OLE DBドライバについてもインストール済みで、こちらを報告すべきでした。
やったことメモから適当に引いてご報告してしまいました。
結果的にmayu様よりアドバイスいただいた以下を追加することで、
64bit版Accessの帳票フォーム上にもADO接続の結果を正しく表示することが
出来ました!
知らないアイテムでしたので調べましたところ、rsの結果をクライアント側で
利用する事を明示するものなのですね。64bit版Accessで結果セットから.Nameアイテムを
利用する際にははしっかり明示する必要があるようです。
mayu様、とても助かりました。ありがとうございます。
ところでADO接続とDAO接続の違いについて、どちらもサーバーから結果セットのみ
取得できるようですので、Access上では親和性の高いDAO接続の方が良さそうですね!
DAOのリンクテーブルでは、テーブルデータを毎度引っ張ってきてローカルでキューされる
と勘違いしておりました。パススルー出来るのですね!
ウチのシステムもDAOにしておいてくれたら移行もすんなりだったのに…とも思いますが
今回の事は私にとってとても勉強になりました。
重ねてお礼申し上げます。ありがとうございました。