外部のMDBファイル内のテーブルにパススルークエリを発行できますか?

解決


山本  2012-10-24 20:47:23  No: 143409

ファイルサーバーにmdbファイルを置き、そのファイルにテーブルのみ配置して共有して使用しています。
パススルークエリにてテーブル内の特定の日付のレコードを削除するということを考えているのですが、可能でしょうか?
試行錯誤して以下のように接続しようとしていますが、
「パススルー クエリで使用されている接続文字列が正しくありません。」
とエラーになってしまいます。

    Dim db As DAO.Database
    Dim qDEF As DAO.QueryDef
    
    Set db = CurrentDb
    Set qDEF = db.CreateQueryDef("")
    
    qDEF.Connect = ";DATABASE=\\fileserver\test.mdb"
    qDEF.ReturnsRecords = False
    qDEF.SQL = "DELETE FROM A WHERE A.日付 = #" & dat対象日 & "#"
    qDEF.Execute
    qDEF.Close

Excelにも接続できるとどこかでみかけたので、当然Accessでもできると考えてチャレンジしているのですが無理でしょうか?


魔界の仮面弁士  2012-10-25 00:43:22  No: 143410

SELECT / INSERT / DELETE / UPDATE のいずれにしても、
クエリにフルパスを指定できたはずです。確かこんな感じで。

 SELECT A.ID, B.NAME FROM
 [C:\test\db1.mdb].[Table1] A
 INNER JOIN
 [C:\test\db2.mdb].[Table2] B
 ON A.ID = B.ID
 ORDER BY A.ID


魔界の仮面弁士  2012-10-25 06:57:24  No: 143411

> qDEF.Connect = ";DATABASE=\\fileserver\test.mdb"
QueryDef.Connect での接続も可能です。
http://homepage1.nifty.com/tsware/tips/tips_111.htm

しかし、「\\fileserver\test.mdb」というパスは
本来はありえないはずです。
正しいパスになっているか確認してみてください。

Z:\localDirectory\test.mdb
\\fileserver\sharedName\test.mdb
\\fileserver\sharedName\foldername\test.mdb   など。

また、mdb を書き込み可能として開く場合には、そのフォルダに
ldb ファイルが生成されることになります。このため、別サーバー上の
ファイルを扱う場合には、mdb ファイルへの編集権限だけではなく、
ディレクトリに対するファイル生成権限にも注意しておいてください。


山本  2012-10-25 18:42:09  No: 143412

ご返信ありがとうございます。
早速テストさせていただきましたところうまく動きました。

コード:
strSQL = "DELETE FROM [\\fileserver\test.mdb].[A]"
Set qDEF = CurrentDb().CreateQueryDef("")
qDEF.SQL = strSQL
qDEF.Execute
qDEF.Close

しかしこれはパススルークエリとして動いているのでしょうか?
試しにstrSQLにWHERE句を追加してみたのですが、処理速度がWHERE句追加前後で変わりません。
そこでConnectでの接続をテストしてみましたがエラーが表示されました。

コード:
strSQL = "DELETE FROM A"
qDEF.Connect = ";DATABASE=\\fileserver\test.mdb;TABLE=A"
qDEF.ReturnsRecords = False
qDEF.SQL = strSQL '←ここでエラーになります
qDEF.Execute
qDEF.Close

エラー:
パススルー クエリで使用されている接続文字列が正しくありません。

ネットワークパスに対応していないのかと思い、ネットワークドライブの割り当てをして再度実行してみましたが結果は変わらずでした。
ちなみにネットワークパスはおっしゃる通り\\fileserver\test.mdbではなく実際にはもっと階層が深いのですが、便宜上略させていただきました。
言葉足らずで申し訳ございません。


魔界の仮面弁士  2012-10-25 23:22:42  No: 143413

> 早速テストさせていただきましたところうまく動きました。

IN 句を使う手法もあります。

「SELECT * FROM TABLE1 IN "\\fileserver\Shared\test.mdb"」
「SELECT * FROM TABLE1 IN '\\fileserver\Shared\test.mdb'」
「SELECT * FROM TABLE1 IN '' '\\fileserver\Shared\test.mdb'」
「SELECT * FROM TABLE1 IN '' [;Database=\\fileserver\Shared\test.mdb]」
「SELECT * FROM TABLE1 IN '' [\\fileserver\Shared\test.mdb]」
などなど。

相対パス指定もできるため、同一フォルダ上である場合には、
「SELECT * FROM TABLE1 IN test.mdb」のようにも書けます。

> 処理速度がWHERE句追加前後で変わりません。
パフォーマンス向上を望むのであれば、OpenDatabase メソッドを使って、
相手を(共有モードでは無く)排他モードで開くようにしてみてください。
異種DB間クエリ等を行うのでなければ、こちらの方がパフォーマンスは出るでしょう。

それ以上に向上させる必要がある場合は、ネットワーク越しに処理させることを諦め、
\\fileserver 自身の CPU 上で処理させるよう、システムを見直してみてください。

> これはパススルークエリとして動いているのでしょうか?

パススルーは、JET自身のエンジンではなく、相手側のエンジンに
クエリーを実行させる仕組みですよね。

しかしMicrosoft Jet はファイル共有型データベース システムです。
ファイル共有型データベースでは、ファイルに関する処理が
すべてクライアントで実行されることに注意してください。
http://www.naboki.net/access/achell/achell-02.html

一般的なデータベースでは、データベースエンジンは各サーバー上にありますが、
JET のデータベースエンジンは、\\fileserver 上にはありません。
mdb がどこにあったとしても、利用されるエンジンはローカル側、言い換えれば
EXE を実行させている CPU 上で処理されることになります。

対 mdb に関して言えば、自エンジンに対する問い合わせにしかなりませんので、
パススルークエリーと言う概念自体が存在しないとも言えます。

そもそも、JET のパススルーは ODBC ベースで実行されるものなので、
対mdbのように非ODBC接続となる場合には、どちらにせよ利用できません。

> そこでConnectでの接続をテストしてみましたがエラーが表示されました。
失礼しました。QueryDef.Connect では駄目なようですね。
Connect で mdb を指定できるのは、TableDef の場合のようで。

> \\fileserver\test.mdbではなく
コンピュータ名の直下にファイルは置けないかと。

> 便宜上略させていただきました。
略しすぎて、むしろ不都合を生じているような…。(^^;

Dir("Z:\*.*") だと、「Cドライブのルート直下にあるファイル」
Dir("Z:*.*") だと、「Zドライブのカレントディレクトリ直下にあるファイル」
Dir("*.*") だと、「カレントドライブのカレントディレクトリ直下にあるファイル」
を表しますよね。

しかし、Dir("\\localhost\*.*") は、UNC パスとしては不正なものとなります。
Dir("\\localhost\C$\*.*") などのように、最低でも共有名まで含めないと。


山本  2012-10-26 08:44:12  No: 143414

>IN 句を使う手法もあります。
このような方法もあったのですね。
相対パスでの指定もできるとのことですので、別の案件でかなり使えそうです。
ありがとうございます。

>パフォーマンス向上を望むのであれば、OpenDatabase メソッドを使って、
>相手を(共有モードでは無く)排他モードで開くようにしてみてください。
今回の場合は排他モードでの実行はNGなので別の機会に検討させていただきます。
ただどの程度速度が向上するのかすごく興味があるのでこの後早速テストさせていただこうと思います。

>対 mdb に関して言えば、自エンジンに対する問い合わせにしかなりませんので、
>パススルークエリーと言う概念自体が存在しないとも言えます。
やはりファイル共有型ではいったんローカルでデータが扱われるのですね。
大変勉強になりました。ありがとうございます。
また、共有名省略の件わかりずらく申し訳ございませんでした。
以後気をつけます。

早速ですが、今回質問に至った経緯も省略しておりましたのでお話させていただきます。
事情を書くと長くなり読むのも面倒に思われたら嫌だなぁと思い投稿時は省略しておりましたが、
よりよい方法のご提案がいただる可能性もあるのではという下心が出てきてしまいました・・・^^;

質問に至った経緯:
当社では毎日7000件(累積100万件)ほど売上データが発生しています。
mdbファイルに各種マスタと売上データのテーブルを配置し、共有してバックエンドとして利用しています。
ここ数日で極端に速度が落ちました。(30秒で済んでいたものが20分以上かかる状況)
そこでSQLServerを導入しそこに売上データテーブルのみを配置し、ODBC接続することを考えました。
(高速な処理が必要なときはパススルークエリ、その他はODBC接続した売上データテーブルをリンクテーブルにて利用する考え)
(Accessプロジェクトも検討したのですが、すべて組み直すのはかなり手間なので断念しました)
そして実際にSQLServerをテスト環境に導入してみると、パススルークエリでは1秒もかからず処理が完了し大変感動しました。
しかし、ふと「そういえばどこかでmdbにもパススルークエリが実行できるって記事をみたような・・・」と思い出してしまい、
試行錯誤するもうまくいかず記事も見つからずで今回質問にいたりました。

おかげさまでmdbに対しパススルークエリの実行はできるといえばできるが実質的にはリンクテーブルと変わらないといった認識となりました。
質問する前にまず調べようと思い今まで質問したことはなかったのですが、今回初めて投稿してみて本当によかったです。
大変お世話になりました。本当にありがとうございました。


山本  2012-10-26 08:47:25  No: 143415

解決時のチェックを忘れておりましたので再投稿させていただきます。
以後気をつけます。失礼いたしました。


※返信する前に利用規約をご確認ください。




  


  このエントリーをはてなブックマークに追加