开发者

Query Tables (QueryTables) in Excel 2010 with VBA with VBA creating many connections

开发者 https://www.devze.com 2023-02-08 22:01 出处:网络
I\'m following code I found on another site. Here\'s the ba开发者_如何学Gosics of my code: Dim SQL As String

I'm following code I found on another site. Here's the ba开发者_如何学Gosics of my code:

Dim SQL As String
Dim connString As String

connString = "ODBC;DSN=DB01;UID=;PWD=;Database=MyDatabase"
SQL = "Select * from SomeTable"

With Worksheets("Received").QueryTables.Add(Connection:=connString, Destination:=Worksheets("Received").Range("A5"), SQL:=SQL)
.Refresh

End With

End Sub

The problem with doing this is every single time they hit the button assigned to this it creates a new connection and doesn't ever seem to drop it. I open the spreadsheet after testing and there are many versions of the connection listed under Connections. Connection Connection1 Connection2

I can't seem to find a way to close or delete the connections either. If I add ".delete" after ".Refresh" I get a 1004 error. This operation cannot be done because the data is refreshing in the background.

Any ideas how to close or delete the connection?


You might ask yourself why you're creating a QueryTable every time in your code. There are reasons to do it, but it usually isn't necessary.

QueryTables are more typically design-time objects. That is, you create your QueryTable once (through code or the UI) and the you Refresh the QueryTable to get updated data.

If you need to change the underlying SQL statement, you have some options. You could set up Parameters that prompt for a value or get it from a cell. Another option for changing the SQL is changing it in code for the existing QueryTable.

Sheet1.QueryTables(1).CommandText = "Select * FROM ...."
Sheet1.QueryTables(1).Refresh

You can select different columns or even different tables by changing CommandText. If it's a different database, you'll need a new connection, but that's pretty rare.

I know that doesn't answer your question directly, but I think determining whether you really need to add the QueryTable each time is the first step.

For more on Parameters, see http://dailydoseofexcel.com/archives/2004/12/13/parameters-in-excel-external-data-queries/ It's for 2003, so there are few inconsistencies with later versions. The basics are the same, you just may need to learn about the ListObject object if you're using 2007 or later.


I had the same issue. The previous answer while a definite step in the right direction is a PITA.

It did however allow me to refine my search and the winner is...

http://msdn.microsoft.com/en-us/library/bb213491(v=office.12).aspx

i.e. for your existing QueryTable Object just do this:

.MaintainConnection = False

Works ever so swell. No more Access DB lock file after the data is refreshed.


You should declare the connection as a separate object then you can close it once the database query is complete.

I don't have the VBA IDE in front of me, so excuse me if there are any inaccuracies, but it should point you in the right direction.

E.g.

Dim SQL As String
Dim con As connection

Set con = New connection
con.ConnectionString = "ODBC;DSN=DB01;UID=;PWD=;Database=MyDatabase"

Worksheets("Received").QueryTables.Add(Connection:=con, Destination:=Worksheets("Received").Range("A5"), SQL:=SQL).Refresh

con.close
set con = nothing


I've found that by default new connections created this way are called "Connection". What I am using is this snippet of code to remove the connection but retain the listobject.

Application.DisplayAlerts = False
ActiveWorkbook.Connections("Connection").Delete
Application.DisplayAlerts = True

It can easily be modified to remove the latest added connection (or if you keep track of the connections by their index).

Application.DisplayAlerts = False
ActiveWorkbook.Connections(ActiveWorkbook.Connections.Count).Delete
Application.DisplayAlerts = True


Instead of adding another query table with the add method, you can simply update the CommandText Property of the connection. However you have to be aware that there is a bug when updating the CommandText property of an ODBC connection. If you temporarily switch to an OLEDB connection, update your CommandText property and then switch back to ODBC it does not create the new connection. Don't ask me why... this just works for me.

Create a new module and insert the following code:

Option Explicit

Sub UpdateWorkbookConnection(WorkbookConnectionObject As WorkbookConnection, Optional ByVal CommandText As String = "", Optional ByVal ConnectionString As String = "")

With WorkbookConnectionObject
    If .Type = xlConnectionTypeODBC Then
        If CommandText = "" Then CommandText = .ODBCConnection.CommandText
        If ConnectionString = "" Then ConnectionString = .ODBCConnection.Connection
        .ODBCConnection.Connection = Replace(.ODBCConnection.Connection, "ODBC;", "OLEDB;", 1, 1, vbTextCompare)
    ElseIf .Type = xlConnectionTypeOLEDB Then
        If CommandText = "" Then CommandText = .OLEDBConnection.CommandText
        If ConnectionString = "" Then ConnectionString = .OLEDBConnection.Connection
    Else
        MsgBox "Invalid connection object sent to UpdateWorkbookConnection function!", vbCritical, "Update Error"
        Exit Sub
    End If
    If StrComp(.OLEDBConnection.CommandText, CommandText, vbTextCompare) <> 0 Then
        .OLEDBConnection.CommandText = CommandText
    End If
    If StrComp(.OLEDBConnection.Connection, ConnectionString, vbTextCompare) <> 0 Then
        .OLEDBConnection.Connection = ConnectionString
    End If
    .Refresh
End With

End Sub

This UpdateWorkbookConnection subroutine only works on updating OLEDB or ODBC connections. The connection does not necessarily have to be linked to a pivot table. It also fixes another problem and allows you to update the connection even if there are multiple pivot tables based on the same connection.

To initiate the update just call the function with the connection object and command text parameters like this:

UpdateWorkbookConnection ActiveWorkbook.Connections("Connection"), "exec sp_MyAwesomeProcedure"

You can optionally update the connection string as well.


If you want to delete if right after refresh you should do the refresh not in the background (using first parameter -> Refresh False) so that you have proper sequence of actions


Try setting the QueryTable.MaintainConnection property to False...

"Set MaintainConnection to True if the connection to the specified data source is to be maintained after the refresh and until the workbook is closed. The default value is True! And there doesn't seem to be a UI check box for this (Read/write Boolean)"


Still relevant years later...battling the same issue and this is the most helpful thread out there. My situation is a variant of the above and I will add my solution when I find it.

I am using an Access database for my data source and establish a querytable on a new sheet. I then add two more new sheets and try to establish a querytable using the same connection on each of them, but to a different Access table. The first querytable works just fine and I use .QueryTables(1).Delete and setting the querytable object to Nothing to make it disconnected.

However, the next sheet fails on establishing a new querytable using the same connection, which was not closed. I suspect (and will add the solution below) that I need to drop the connection before deleting the querytable. Rasmus' code above looks like the likely solution.

0

精彩评论

暂无评论...
验证码 换一张
取 消