Reputation: 71
I have the below VBA query used in Excel 2016 that exacutes a MS Sql stored procedure, sometimes it executes smoothly and returns the recordset, but more often I get an error [Microsoft][ODBC SQL Server Driver] query timeout expired
.
At the same time when we go to SSMS and execute the query it runs without issues.
This assumes the issue is rather caused by Excel/VB than by SQL or the query itself.
Searching for this error results in checking network firewalls, but we tried on other machines without firewalls, problems persists.
Here is the VB code:
Public Sub GetDataset2()
Dim cn As ADODB.Connection
Dim cm As Object
Dim rs As ADODB.Recordset
Dim UID, PWD, DB As String
UID = "userId"
PWD = "passworD"
DB = "192.168.1.1"
Set cn = New ADODB.Connection
Set cm = CreateObject("ADODB.Command")
cm.CommandTimeout = 0
cn.Open ("Driver={SQL Server};Server=" & DB & ";Database=myDatabaseName;Trusted_Connection=no;Timeout=900;Uid=" & UID & ";Pwd=" & PWD)
Set rs = cn.Execute("Get_dataset2 '" & Format(Range("dateFrom"), "yyyy-mm-dd") & "' ,'" & Format(Range("dateTo"), "yyyy-mm-dd") & "' ")
Dim lRow As Long
'Find the last non-blank cell in column A(1)
lRow = Sheets("data").Cells(Rows.Count, 1).End(xlUp).Row
lr = "A" & lRow + 1
Sheets("data").Range(lr).CopyFromRecordset rs 'insert data
cn.Close
End Sub
Any suggestion is appreciated. Joel
Upvotes: 0
Views: 11911
Reputation: 71
After weeks of testing various code changes, we found that when changing the SQL call to QueryTable
method instead of CopyFromRecordset
method, it is working fine.
So I am pasting the code if anyone needs it in future.
Sub GetDataset3()
Dim cn As ADODB.Connection
Dim Rs As ADODB.Recordset
Dim UID, PWD, SRV As String
UID = "userId"
PWD = "passworD"
SRV = "192.168.1.1"
If Sheets("data").QueryTables.Count = 0 Then
Sheets("data").Cells.Select
Selection.ClearContents
Dim Str As String 'adds backround query
Str = ""
For Each cell In Range("A1:A10").Cells
Str = Str & Chr(10) & cell
Next
With Sheets("data").QueryTables.Add(Connection:="ODBC;UID=;PWD=;DRIVER=SQL
Server;SERVER=SRV", Destination:=Range("a2"))
.CommandText = "select 1"
'BackgroundQuery = True
'.Refresh BackgroundQuery = True
.FieldNames = False
.AdjustColumnWidth = False
End With
End If
With Sheets("data").QueryTables(1)
.Connection = "ODBC;DRIVER=SQL Server;SERVER=" & SRV &
";database=myDatabaseName;UID=" & UID & ";Pwd=" & PWD &
";Trusted_Connection=no;APP=Microsoft Office"
.CommandText = ("Get_dataset2 '" & Range("dateFrom") & "' ,'" &
Range("dateTo") & "' ")
BackgroundQuery = True
.Refresh BackgroundQuery:=False
End With
End Sub
Upvotes: 0
Reputation: 186
After some more thought about the question and the comments on my prior answer, here are some additional points. To BitAccesser, cn.CommandTimeout
is the same as Connection.CommandTimeout
since the originally submitted code had already dimensioned and set the cn
object as an ADODB.Connection
. Also worth noting is the difference between ConnectionTimeout
and CommandTimeout
. The connection timeout is network level, while the command timeout is SQL Server level. In this case, even though a ADODB.Command
object is instantiated, it isn't used. Another point relates to the connection string. The connection timeout could be referenced in the connection string, but often, is not used. The connection will be defaulted to 15 seconds. So, its worth resetting those attributes explicitly.
Cn.CommandTimeout = 50
Cn.ConnectionTimeout = 50
Upvotes: 1
Reputation: 186
One possible solution is to lengthen the connection command timeout value. Your current script has the value set to 0. This could be increased. Running the query in SSMS should give you a rough idea of the time needed to complete the query. Then, adjust the value accordingly.
cm.CommandTimeout = 100
Upvotes: 0