web-dev-qa-db-ja.com

VBAの新しいデータベース接続

スクリーンショットに表示されないように、以下のコードを変更する方法。

次のコードでマクロを実行しています

Dim conn As ADODB.Connection
Dim rec1 As ADODB.Recordset
Dim thisSql As String

Set conn = New ADODB.Connection

Dim sConn As String
  sConn = "Provider=SQLOLEDB;Trusted_Connection=Yes;Server=xyz;Database=xyz;UID=xyz;PWD=xyz"
conn.Open sConn

' this is creating multiple connections.
Set rec1 = New ADODB.Recordset
rec1.Open thisSql, conn

これはSQLServerクエリを実行します(長さは約20行で、4つの結合が含まれています)。数回実行した後、DB管理者が、クエリがDBをロードしすぎていると言っていることを除いて、すべて問題ありません。

今、私のクエリが問題を引き起こしている可能性があります、またはExcelが一度に複数の接続を実行し始めている可能性があります。これを示すいくつかの証拠は、以下のスクリーンショットと、データベースの負荷が時間とともに増加しているように見えるという事実です。

常に新しい接続を作成せずにDB接続を確立するにはどうすればよいですか?

Excel DBマクロの操作で同様の問題が発生した人はいますか?

Multiple connections


[〜#〜] update [〜#〜]

以下の回答は非常に役立ちましたが(特にVBAを始めた人にとって)、クエリが負荷をかけている主な理由は、複数の接続の組み合わせとコードの行を見落としていたためと思われます。

    With Sheets("FVols").QueryTables.Add(Connection:=rec1, Destination:=Sheets("FVols").Range("A1"))
    .name = "data"
    .FieldNames = True
    .Refresh BackgroundQuery:=True <<<<<<<<<<<<<<<<<<<<<<<-----

End With
4
frickskit

接続を開く必要があるのは1回だけです。これは文字通り、その1つのアクティブな接続で複数のクエリを実行できることを意味します。衝突やその他の接続関連の問題が発生しないように、接続を閉じて参照を解放する必要があります(特にADODBの場合)。

実行するクエリがわかっている場合は、配列(またはコレクション)を作成して、キューにクエリを追加できます。

作業するためのオープン接続がすでにある間は、クエリを実行し続けることができます。

コードをスキャンして、あなたと私のコードに大きな違いはないので、何がどこで起こっているのかを確認できるはずです。不明な点があればコメント欄で質問してください

_   Sub DbConnection()

    Dim cn As ADODB.Connection
    Set cn = New ADODB.Connection
    Dim rs As ADODB.Recordset

    Dim strConn As String
    strConn = "Driver={SQL Server};Server=; Database=; UID=; PWD="

    cn.Open strConn

    Dim queryArr, i
    queryArr = Array("SELECT * FROM [MyTable]", "SELECT * FROM [MyOtherTable]")

    For i = LBound(queryArr) To UBound(queryArr)
        ExecuteQuery queryArr(i), cn, rs
    Next i

    cn.Close
    Set cn = Nothing
End Sub

Private Sub ExecuteQuery(query As Variant, ByRef cn As ADODB.Connection, ByRef rs As ADODB.Recordset)
    Set rs = New ADODB.Recordset
    With rs
        .ActiveConnection = cn
        .Open CStr(query)
        Sheets(1).Range("A1").CopyFromRecordset rs
        .Close
    End With
    Set rs = Nothing
End Sub
_

これで、DBConnection()を1回実行するだけで、配列にリストしたすべてのクエリが実行されます。

または、クエリが実行時に作成される場合は、パラメータとしてDbConnection()に渡すことができます。

_Sub DbConnection(queryQueue As Collection)

    Dim cn As ADODB.Connection
    Set cn = New ADODB.Connection
    Dim rs As ADODB.Recordset


    Dim strConn As String
    strConn = "Driver={SQL Server};Server=HELIUM\PRI; Database=sourcedata; UID=tabula; PWD=Tabula123!"

    cn.Open strConn

    For i = 1 To queryQueue.Count
        ExecuteQuery queryQueue.Item(i), cn, rs
    Next i

    cn.Close
    Set cn = Nothing
End Sub

Private Sub ExecuteQuery(query As Variant, ByRef cn As ADODB.Connection, ByRef rs As ADODB.Recordset)
    Set rs = New ADODB.Recordset
    With rs
        .ActiveConnection = cn
        .Open CStr(query)
        Sheets(1).Range("A1").CopyFromRecordset rs
        .Close
    End With
    Set rs = Nothing
End Sub
_

更新:

接続をグローバル変数として宣言できます。これで、DBConnection()を何度でも実行でき、毎回新しい接続を作成する必要はありません。代わりに、グローバル接続オブジェクトを使用します。

_Option Explicit

Public cn As ADODB.Connection

Sub DbConnection()

    Set cn = New ADODB.Connection
    Dim rs As ADODB.Recordset

    Dim strConn As String
    strConn = "Driver={SQL Server};Server=; Database=; UID=; PWD="

    cn.Open strConn

    Set rs = New ADODB.Recordset
    With rs
        .ActiveConnection = cn
        .Open "SELECT * FROM [MyTable]"
        Sheets(1).Range("A1").CopyFromRecordset rs
        .Close
    End With
    Set rs = Nothing

    cn.Close
    Set cn = Nothing
End Sub
_
8
user2140173

終了したら接続変数を解放しますか?つまり.

Set rec1 = Nothing

そうしないと、接続は完全に閉じません。

0
ZenSquirrel