[[20130429224133]] 『ADOでリンクテーブルの接続』(TAKA) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『ADOでリンクテーブルの接続』(TAKA)

宜しくお願いします。EXCEL,2007 ACCESS,2010です。

社内のPC-AとPC-BがありましてPC-Aのデスクトップ上の共有フォルダにリンク.accdbのファイルがあります。クエリなど5個程のテーブルをリンクさせております。ちなみにPC-AのみACCESSがインストールされています。PC-AのEXCELから下記コードを実行すると作動しますがPC-Bから操作すると「パス'C\Users....accdbは正しくありません。パス名に間違いないことと、ファイルが置かれたサーバーに接続していることを確認してください。」とエラーが表示されます。

質問内容はACCESSのリンクテーブルを使用してフルパスで他のPCからデータの抽出は可能でしょうか?仕様は共有フォルダのEXCELからADOを利用してテーブルのレコード更新、変更、削除(同時に編集できないようにEXCEL VBAで制御はしています。)クエリなどの抽出はACCESSのリンクテーブルで行いたいと考えています。

申し訳ございませんが抽出方法を教えて下さい。

Dim db As Object, rs As Object, cmd As Object, SQL As String

SQL 〜 省略 〜

Set db = CreateObject("ADODB.Connection")

db.Provider = "Microsoft.Ace.OLEDB.12.0"

db.Open ThisWorkbook.Path & "\リンク.accdb"

Set rs = CreateObject("ADODB.Recordset")

Set cmd = CreateObject("ADODB.Command")

Set cmd.ActiveConnection = db

cmd.CommandText = SQL

Set rs = cmd.Execute

If rs.EOF Then MsgBox "抽出した結果、レコードが見つかりません。"

Else

Range("a3").CopyFromRecordset rs

End If

rs.Close: db.Close

Set rs = Nothing: Set db = Nothing


PC-AにあるExcelファイルをPC-Bで開く形ですか?
PC-Bにも全く同じExcelファイルを配布したほうが私はいいと思います。
(2つ同時にひらくと片側は読み取り専用になってしまう為です)
以下は利用するPC全てにExcelファイルを配布する前提で書きます。

ThisWorkbook.Path & "\リンク.accdb"

ネットワーク越しにファイルを参照するには
パスは\\****\**\リンク.accdbとなります。
PC-BからPC-Aの共有フォルダを開きリンク.accdbのプロパティを見て
フルパスを確認しましょう。

PC-Aも、\\****\**\リンク.accdbで接続できますが、ネットワーク越しに接続
する形になるので速度が落ちます。

PC-AはThisWorkBook.Path
PC-Bは\\****\**\リンク.accdb

で利用するようにします。

ここで問題になるのが、パスのハードコーディングです。(直にパスを書いてしまう)
利用する環境が変わった。Excelファイルを修正し配布し直した時などの事
を考えるとうまい仕組みが必要ですね。

・iniファイルに接続パスを仕込みOpen毎にiniファイルからパスを得る

・隠しシートに接続パスを仕込む

接続パスを返す関数を作成

 Public Function GetDbPath() As String

     Dim sh As WorkSheet
     Set sh = WorkSheets("隠しシート名")
     GetDbPath = sh.Range("A1").Value 'A1にはフルパス
 End Function

使用例
db.Open GetDbPath

接続先を選択して登録できる仕組みを作成します。(GetOpenFileNameなどで)
選択されたaccessファイルのパスをiniファイルや隠しシートに登録します。
この時大事なのは、上でも書きましたがPC-Aは必ず自デスクトップ上の
フォルダを直接選択し登録することです。ネットワーク→共有フォルダと
辿ってしまうと折角自PC上にあるのに速度低下を招きます。

このような仕組みを作成しておけば、環境が変わったり配布する数が多くなって
きても直ぐ対応出来ます。

(DonDon)


 >テーブルをリンクさせております
 このリンク元のaccdbファイルは、PC-Bから見れる場所にあるんですか?

 これも共有しておかないと、操作は、できませんよ!!

 確認してみてください。

 私は、Excelブックは、最近は、一つで共有させえていますよ、
 最初から、読み取り専用にしていますから・・・。Excelにコードを置くのですから、
 これに通常は、書き込みはしませんから・・・。

 ichinose


返事が遅くなり申し訳ございません。

回答ありがとうございました。

DonDon様、作動するか検証したいと思います。すいません!少しお時間を下さい。

ichinose様、PC-AにのみACCESSが導入しており、共有フォルダにテーブルのみのaccdbファイルをいくつも作成してあります。そのテーブルaccdbから同じ共有フォルダにリンクaccdbにリンクさせております。
EXCELファイルも同じ共有フォルダに複数入っておりますが、他の人が使用しているとBOOKを開けないよう制御はしています。

元々accdbファイルは一つでその中でテーブルやクエリを作成していましたが、先日、accdbがフリーズしてしまい。対策としてテーブルごとにファイルを作成して更新用と集計、抽出用のリンクテーブルを作成したほうがよいかと思いました。

PC-Bから共有フォルダ(PC-A)のリンク.accdbから抽出できたらと考えています。

DonDon様の回答も踏まえて色々トライしてみようと思います。


 >PC-Bから共有フォルダ(PC-A)のリンク.accdbから抽出できたらと
 リンクテーブル設定時にUNCパスで設定されていますか?
 そうでなかったら、UNCパスでリンクテーブルを再設定してみて下さい

 ichinose


DonDon様、ichinose様、動作確認できました。

ネットワーク越しにファイルを参照するにはサーバー名を指定すればよかったのですね!勉強になりました。

UNCパスでリンクテーブルを再設定したらあっさり作動しました。

後は、Excelファイルを全てのPCに配布しようか悩んでおります。今後のメンテナンス等も含めて色々トライしてみようと思います。

リンクテーブルもThisWorkbook.Pathみたいに簡単にフルパスができればよいのですが・・・ネットで調べるとVBAでできるみたいなことは書いてあったのですが。自宅にUSBで持ち帰るとリンクを再設定するのが大変なので今度、勉強してみようと思います。

返事が遅くなり申し訳ございませんでした。ありがとうございました。仕事で月末処理が終わらなかったので・・・

(TAKA)


 >リンクテーブルもThisWorkbook.Pathみたいに簡単にフルパスができればよいのですが・・・ネットで調べるとVBAでできるみたいなことは書いてあったのですが

 私も以前、テーブルリンク設定コードを調べた事がありました。
 私は、これを仕事では使ったことがありませんが・・・。

 Adox.Catalog を使って、既存テーブル属性を調べるとリンクテーブルの作成は、
 出来ると思いますよ!!

 標準モジュール(Module1)にAdox I/O プロシジャー群

 '============================================================================
 Private cat As Object 'ADOX.Catalog
 Function open_cat(flnm As String) As Long
    On Error Resume Next
    Set cat = CreateObject("ADOX.Catalog")
    cat.ActiveConnection = "Provider=Microsoft.Ace.OLEDB.12.0;" & _
        "Data Source=" & flnm
    open_cat = Err.Number
    On Error GoTo 0
 End Function
 '=================================================================
 Function get_cn() As Object
   Set get_cn = cat.ActiveConnection
 End Function
 '=================================================================
 Function create_lnktbl(tblnm As String, l_tblnm As String, ldbnm As String, Optional pwd As String = "", Optional exstr As String = "") As Long
 'リンクテーブルを作成する
 'Input:tblnm----テーブル名
 '      l_tblnm--リンク先テーブル名
 '      ldbnm----リンク先dbのフルパス
 '      pwd------リンク先にパスワードが設定されている場合、そのパスワード(省略可)
 '      exstr----他のデータベース(Excelやtxtファイル、etc)をリンクするときの追加ストリング(省略可)
 'Output:create_lnktbl----0--正常終了,その他:異常終了
    On Error GoTo err_lnkcreate_tbl
    Dim tbl As Object 'ADOX.Table
    create_tbl = 0
    Set tbl = CreateObject("ADOX.Table")
    tbl.Name = tblnm
    Set tbl.ParentCatalog = cat
    With tbl
      .Properties("Jet OLEDB:Create Link").Value = True
      .Properties("Jet OLEDB:Remote Table Name").Value = l_tblnm
      .Properties("Jet OLEDB:Link Datasource").Value = ldbnm
      If pwd <> "" Then .Properties("Jet OLEDB:Link Provider String") = ";pwd=" & pwd
      If exstr <> "" Then
         .Properties("Jet OLEDB:Link Provider String").Value = exstr
      End If
    End With
    cat.Tables.Append tbl
    Set tbl = Nothing

 ret_lnkcreate_tbl:
    On Error GoTo 0
    Exit Function
 err_lnkcreate_tbl:
   MsgBox Error(Err.Number)
   create_tbl = Err.Number
   Resume ret_lnkcreate_tbl
 End Function
 '=================================================================
 Sub close_cat()
    On Error Resume Next
    cat.ActiveConnection.Close
    Set cat = Nothing
    On Error GoTo 0
 End Sub

 別の標準モジュール(Module2)に

 '==========================================================================
 Sub mk_lnktbl()
   Dim uncp As String
   With CreateObject("wscript.network")
      uncp = "\\" & .computername & "\" & Replace(ThisWorkbook.Path, ":", "")
   End With
   If open_cat(ThisWorkbook.Path & "\Linktest.accdb") = 0 Then
      Call create_lnktbl("newtbl1", "Testtbl", uncp & "\testacc.accdb")
      End If
   Call close_cat
 End Sub

 mk_lnktblの実行で このVBAコードを含むExcelブックと同じフォルダ上にある

 Linktest.accdb というデータベースファイル上に

 同じフォルダ上にあるtestacc.accdb内のTesttblというテーブルを

 newtbl1 というテーブル名でリンクテーブルを作成します。

 UNCパス変換は、WMIかAPIを使えばできるかもしれませんが、
 今回は、WSHでコンピュータ名を取得し、あとは、文字列の置き換えで作成しました。

 又、create_lnktblは、パラメータの指定で、Excelシートやtxtなどもリンク可能にしてあります。

 参考になれば、幸いです。

 ichinose

 


ichinose様、すごいサンプルコードありがとうございます。(自分のレベルでは・・・理解できるよう勉強します。)

とりあえず下記内容でリンクの変更をトライ中ですが、うまくいかず相談させて下さい。PC-Aのフォルダの中にaaa.accdb, bbb ccc のファイルとリンク.accdbがあり、例えばaaa.accdbファイルにT_aaaのテーブルが一対でテーブルを作成しています。

リンク.accdbの標準モジュールに下記コードで一括変更したいのですが、DATABASE=\\・・・の所で処理が止まってしまい教えて頂けないでしょうか?文字列の結合の部分だと思うのですが・・

Dim tdf As TableDef, dbs As Database
Dim tbl() As Variant, fil() As Variant, i As Byte

'Microsoft DAO 3.6 Object Library参照設定

tbl = Array("T_aaa", "T_bbb", "T_ccc") 'テーブル名
fil = Array("aaa", "bbb", "ccc") 'accdbファイル名

Set dbs = CurrentDb

For i = 0 To UBound(tbl)

    Set tdf = dbs.TableDefs(tbl(i))

    With tdf
      .Connect = ";DATABASE=\\サーバー名\(省略)\フォルダ名\" & fil(i) & ".accdb";TABLE=" & tbl(i)
      .RefreshLink
    End With

    Set tdf = Nothing
Next i

    MsgBox "リンクテーブルの変更が完了しました。"

    dbs.Close: Set dbs = Nothing

(TAKA)


 今度は、DAOですか? 私はDAOは、普段使わないのですが・・・、 

 Sub test()
    Dim tdf As TableDef, dbs As Database
    Dim tbl() As Variant, fil() As Variant, i As Byte
    Dim uncp As String
    uncp = "\\" & CreateObject("wscript.network").computername
    With CreateObject("scripting.filesystemobject")
       uncp = uncp & "\" & Replace(.GetParentFolderName(CurrentDb.Name), ":", "")
    End With
    tbl = Array("T_aaa", "T_bbb", "T_ccc") 'テーブル名 
    fil = Array("aaa", "bbb", "ccc") 'accdbファイル名 
    Set dbs = CurrentDb
    For i = 0 To UBound(tbl)
       Set tdf = dbs.TableDefs(tbl(i))
       With tdf
         .Connect = ";DATABASE=" & uncp & "\" & fil(i) & ".accdb;TABLE=" & tbl(i)
         .RefreshLink
       End With
    Next i

    MsgBox "リンクテーブルの変更が完了しました。"

    dbs.Close
    Set tdf = Nothing
    Set dbs = Nothing

 End Sub

 ichinose@GW中の旅行で食べ過ぎ・・・


ichinose様GW中にもかかわらずありがとうございます。食べ過ぎにご注意下さいませ!

教えて頂いたコードにてトライしました。最初の質問の時のエラー表示がされます。msgbox uncpで確認すると、\\サーバー名\C\・・・・と恐らくドライブ名も連結されている為かと思われます。

とりあえず自分が掲示したコードの連結部分を修正したら作動しましたので下記のように都度、環境に合わせて切り替えようと思います。テーブルが増えるとArrayの部分で追加して・・・VBAのようで手動なんですけど(笑)

ichinose様、色々とお世話をおかけしました。大変助かりました。

  With tdf

      .Connect = ";DATABASE=\\サーバー名\(省略)\フォルダ名\" & fil(i) & ".accdb;TABLE=" & tbl(i)
   '.Connect = ";DATABASE=\\サーバー名\(省略)\フォルダ名\" & fil(i) & ".accdb;TABLE=" & tbl(i)
      .RefreshLink
    End With

(TAKA)


 >\\サーバー名\C\・・・・と恐らくドライブ名も連結されている為
 あっ、そうですねえ、そういう場合もありますねえ!!
 やっぱり、共有一覧と照らし合わせないと駄目ですねえ!!

 一覧は、WMIを探ってみたらありました。

http://www.wmifun.net/sample/win32_share.html

 この一覧と照合する方法でしょうかねえ!!

 ichinose

コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.