Stored procedure from VBA Excel not running - sql-server

I'm calling from VBA a stored procedure from a PC and it is working okay. In another PC and different user it is not working. A single query though, it is working in both PCs.
I'm calling the stored procedure as follows:
Dim rst As New ADODB.Recordset
Dim ConnectionString As String
Dim StrQuery As String
' Connection string for accessing MS SQL database
ConnectionString = <Connection details>
' Opens connection to the database
cnn.Open ConnectionString
' Timeout error in seconds for executing the entire query; The stored procedure normally runs for around 20 min
cnn.CommandTimeout = 2400
' Process execution
StrQuery = "exec [00_Main] #date = '01/31/2018' "
rst.Open StrQuery, cnn
rst.Close
I'm guessing that I have an error message when executing the stored procedure, but I don't know how to capture it.
I tried the following, but I don't get anything as an output
' Process execution
StrQuery = "exec [00_Main] #date = '01/31/2018' "
rst.Open StrQuery, cnn
Debug.Print rst.Fields.Count
Debug.Print rst.RecordCount
Debug.Print rst
rst.Close
When I run the stored procedure in SQL Management studio I just get output messages as the stored procedure just updates tables. Like:
(29145907 rows affected)
(330527 rows affected)
I tried also adding Error Information following link here, but the process runs without giving me any error. Like:
' Process execution
DateSelection = Sheets("STB Check").Range("F1")
'StrQuery = "exec [00_Main] #date = '" & DateSelection & "' "
StrQuery = "exec [00_Main] #date = '01/31/2018' "
rst.Open StrQuery, cnn
Done:
rst.Close
Exit Sub
AdoError:
Dim errLoop As Error
Dim strError As String
i = 1
' Process
StrTmp = StrTmp & vbCrLf & "VB Error # " & Str(Err.Number)
StrTmp = StrTmp & vbCrLf & " Generated by " & Err.Source
StrTmp = StrTmp & vbCrLf & " Description " & Err.Description
' Enumerate Errors collection and display properties of
' each Error object.
Set Errs1 = cnn.Errors
For Each errLoop In Errs1
With errLoop
StrTmp = StrTmp & vbCrLf & "Error #" & i & ":"
StrTmp = StrTmp & vbCrLf & " ADO Error #" & .Number
StrTmp = StrTmp & vbCrLf & " Description " & .Description
StrTmp = StrTmp & vbCrLf & " Source " & .Source
i = i + 1
End With
Next
MsgBox StrTmp
' Clean up Gracefully
On Error Resume Next
GoTo Done
Any ideas?

Use proper parameterization, and treat dates as Date, not as strings.
Instead of running that straight off ADODB.Recordset, use an ADODB.Command; set the command text to just the name of the stored procedure, and add an ADODB.Parameter to its Parameters collection, providing the cell value (after validating that IsDate returns True for that cell value) - like on learn.microsoft.com:
Dim theDate As Date
theDate = Sheets("STB Check").Range("F1").Value
Dim cmd As ADODB.Command
Set cmd = New ADODB.Command
Set cmd.ActiveConnection = cnn
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "[00_Main]"
Dim dateParam As ADODB.Parameter
Set dateParam = cmd.CreateParameter("date", adDate, adParamInput)
dateParam.Value = theDate
cmd.Parameters.Append dateParam
Dim results As ADODB.Recordset
Set results = cmd.Execute

Related

ADO recordset getstring slow for large recordsets

I'm using ADO in VBScript. The query is simple and completes in a couple of seconds.
However, when I execute the GetString method, it takes a very long time to complete and sometimes never completes at all.
Set oShell = CreateObject( "WScript.Shell" )
user = oShell.ExpandEnvironmentStrings("%UserName%")
ConnectSqlServer "select top 100000 * from notices FOR JSON AUTO, INCLUDE_NULL_VALUES;", "PSQL003"
Sub ConnectSqlServer(query, database)
On Error Resume Next
sConnString = "Provider=SQLOLEDB.1;Data Source= " & database & "; " & _
"Initial Catalog=VIEW;" & _
"Integrated Security=SSPI;"
MakeConnectionString = "DSN=" & sDSN & ";Uid=" & sUid & ";Pwd=" & sPwd & ";"
Dim conn
Dim rs
Dim sConnString
Dim resultString
Set conn = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")
conn.Open sConnString
conn.CommandTimeout = 0
Set rs = conn.Execute(query)
Set Errs1 = conn.Errors
For Each errLoop In Errs1
With errLoop
StrTmp = StrTmp & "Error #" & i & ":"
StrTmp = StrTmp & vbCrLf & " ADO Error #" & .Number
StrTmp = StrTmp & vbCrLf & " Description " & .Description
StrTmp = StrTmp & vbCrLf & " Source " & .Source
i = i + 1
End With
Next
Msgbox "Query Finished"
resultString = rs.GetString
Msgbox "String Created"
End Sub

Cannot catch SQL Server SP errors that bypass try..catch in code

I have a SQL Server Stored Procedure. If I put a try block around the code it only catches certain errors and instead just pushes some errors to the SSMS Messages window. I believe the documentation (TryCatch) says certain errors are not caught by the try..catch block (e.g. selecting from a non-existent table)
An example in my case is selecting columns that do not exist via a synonym which sends this to the Messages output pane:
Msg 207, Level 16, State 1, Procedure
dbo.TestSP, Line 185 [Batch Start Line 2]
Invalid column name 'InvalidColumn'.
However, I am running the SP from code not SSMS and get no errors or exceptions returned.
Specifically, my Command Execute method simply returns without raising an exception, the return value is an empty value, and so I have absolutely no idea what the error is for logging or reporting to the user. I have also tried removing the try block completely with the same results.
I am using old school ADODB in VBA, but the same principle will apply to .Net I have looked at the Command object properties and there doesn't seem to be much there and the State returned is 0.
Is there any way to trap or find these errors somewhere in my Command or Connection objects so I can log them other than simply saying 'unknown error'?
As an example, my Stored Procedure is as follows and the select statement having an invalid column raises an error as shown above and does not raise an error.
ALTER PROCEDURE [dbo].[TestSP]
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
declare #returnCode int;
If object_id('syn_xxx','SN') is not null drop synonym syn_xxx
exec('create synonym syn_xxx for sometable')
SELECT TOP 1 InvalidColumn from syn_xxx
END TRY
BEGIN CATCH
set #returnCode=ERROR_NUMBER()
END CATCH
return #returnCode
END
My code is VBA and as follows. The Errors collection contains nothing, the return value is an empty string.
Dim conn_ As ADODB.Connection
Dim cmd As New ADODB.Command
Set conn_ = New ADODB.Connection
conn_.Open dsn
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "TestSP"
cmd.ActiveConnection = conn_
cmd.Execute
What provider are you using in dsn ?
Private Sub CommandButton1_Click()
Dim con As New ADODB.Connection
Dim cmd As New ADODB.Command
Dim errLoop As ADODB.Error
Dim i As Integer
Dim StrTmp As String
'On Error GoTo AdoError
On Error Resume Next
con.ConnectionString = "Provider=SQLNCLI11;" _
& "Server=(local);" _
& "Database=master;" _
& "Integrated Security=SSPI;"
con.Open
cmd.ActiveConnection = con
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "TestSP"
cmd.Execute
MsgBox ("number of errors after procedure 'testproc' --- " & con.Errors.Count)
If con.Errors.Count > 0 Then
i = 1
' Process
StrTmp = StrTmp & vbCrLf & "VB Error # " & Str(Err.Number)
StrTmp = StrTmp & vbCrLf & " Generated by " & Err.Source
StrTmp = StrTmp & vbCrLf & " Description " & Err.Description
' Enumerate Errors collection and display properties of
' each Error object.
For Each errLoop In con.Errors
With errLoop
StrTmp = StrTmp & vbCrLf & "Error #" & i & ":"
StrTmp = StrTmp & vbCrLf & " ADO Error #" & .Number
StrTmp = StrTmp & vbCrLf & " Description " & .Description
StrTmp = StrTmp & vbCrLf & " Source " & .Source
i = i + 1
End With
Next
MsgBox (StrTmp)
End If
cmd.CommandText = "select 10 as test"
cmd.CommandType = adCmdText
cmd.Execute
MsgBox ("number of errors after 'select 10 as test' --- " & con.Errors.Count)
' Close all open objects.
If con.State = adStateOpen Then
con.Close
End If
End Sub

Select long text from SQL using Excel VBA ADO returns garbage characters [duplicate]

This question already has an answer here:
What are the limits for ADO data types?
(1 answer)
Closed 3 years ago.
I can't figure out how to retrieve long text (>8kb) from a SQL Server field using an ADODB connection through Excel VBA. My method returns a garbage string.
I can successfully upload a field with >8kb data length using a parameterized query as in the following code:
Public Sub TestLongParamUploadQuery()
Dim conn As ADODB.Connection
Dim cmd As ADODB.Command
Dim param As ADODB.Parameter
Dim rs As ADODB.Recordset
Query = "INSERT INTO MYTABLE ([Long_Text], [Table_Index]) VALUES (?, ?);"
Set conn = New ADODB.Connection
conn.ConnectionString = connStr
On Error GoTo connerror
conn.Open
Set cmd = New ADODB.Command
With cmd
.ActiveConnection = conn
.CommandText = Query
.CommandType = adCmdText
Set Pm = .CreateParameter("long_text", adLongVarWChar, adParamInput, 20000)
Pm.Value = Replace("THIS IS A REALLY LONG TEXT STRING " & Space(8000) & "THIS IS A REALLY LONG TEXT STRING", " ", ".")
.Parameters.Append Pm
Set Pm = .CreateParameter("table_index", adVarChar, adParamInput, 32)
Pm.Value = "MYFAKERECORD"
.Parameters.Append Pm
Set rs = .Execute
End With
connerror:
If Err.Number <> 0 Then
Msg = "Error # " & str(Err.Number) & " was generated by " _
& Err.Source & Chr(13) & "Error Line: " & Erl & Chr(13) & Err.Description
MsgBox Msg, , "Error", Err.HelpFile, Err.HelpContext
End If
conn.Close
End Sub
But when I attempt to retrieve the data via a SELECT statement, the data comes back garbled.
Public Sub TestLongParamDownloadQuery()
Dim conn As ADODB.Connection
Dim cmd As ADODB.Command
Dim param As ADODB.Parameter
Dim rs As ADODB.Recordset
Query = "SELECT * FROM MYTABLE WHERE Table_Index='MYFAKERECORD';"
Set conn = New ADODB.Connection
conn.ConnectionString = connStr
On Error GoTo connerror
conn.Open
Set cmd = New ADODB.Command
With cmd
.ActiveConnection = conn
.CommandText = Query
.CommandType = adCmdText
End With
Set rs = cmd.Execute()
Do Until rs.EOF = True
For i = 0 To rs.Fields.Count - 1
If Not IsNull(rs.Fields.Item(i)) Then
Debug.Print ("field '" & rs.Fields(i).Name & "' length: " & Len(rs.Fields.Item(i)) & "; value: '" & rs.Fields.Item(i) & "'")
End If
Next
rs.MoveNext
Loop
connerror:
If Err.Number <> 0 Then
Msg = "Error # " & str(Err.Number) & " was generated by " _
& Err.Source & Chr(13) & "Error Line: " & Erl & Chr(13) & Err.Description
MsgBox Msg, , "Error", Err.HelpFile, Err.HelpContext
End If
conn.Close
End Sub
The data is successfully making it into the database. I'm able to open and see it in SQL Server Management Studio.
However. The Debug.Print output from my download looks like the following
field 'Long_Text' length: 8067; value: ' MYFAKERECORD ? ?%0?? ?%0?? ? ? ? ? ?
'
field 'Table_Index' length: 12; value: 'MYFAKERECORD'
Note that the length appears to be correct. It's not merely an issue in printing in the immediate window of the Excel VBA IDE. When I write the data to an excel cell via the macro, the cell contains '``' after upload.
I've tried the upload with the parameter for Unicode adLongVarWChar and plaintext adLongVarChar. Both appear to place data correctly in the database. Both come back as broken text from the select statement.
What is the appropriate way to download and interrogate long text via adodb?
EDIT I did find this thread which notes a fundamental limitation that ADO cannot interpret nvarchar(max) type. The proposed solution of CAST'ing the variable to nvarchar(20000) will not work for me because the upward limit for CAST is 8000 characters. How can I transfer data from a field GREATER than 8kb to Excel VBA?
This answer was drawn from the post What are the limits for ADO data types?
The solution as is to:
Cast the desired fields as text.
Retrieve the actual data from the record set using string = rs.Fields(0).GetChunk(rs.Fields(0).ActualSize)
Incorporating into my code it looks like:
Public Sub TestLongParamDownloadQuery()
Dim conn As ADODB.Connection
Dim cmd As ADODB.Command
Dim param As ADODB.Parameter
Dim rs As ADODB.Recordset
Query = "SELECT * FROM MYTABLE WHERE Table_Index='MYFAKERECORD';"
Set conn = New ADODB.Connection
conn.ConnectionString = connStr
On Error GoTo connerror
conn.Open
Set cmd = New ADODB.Command
With cmd
.ActiveConnection = conn
.CommandText = Query
.CommandType = adCmdText
End With
Set rs = cmd.Execute()
Do Until rs.EOF = True
For i = 0 To rs.Fields.Count - 1
If Not IsNull(rs.Fields.Item(i)) Then
If rs.Fields.Item(i).Name = "Long_Text" Then
Debug.Print(rs.Fields(i).GetChunk(rs.Fields(i).ActualSize))
End If
Debug.Print ("field '" & rs.Fields(i).Name & "' length: " & Len(rs.Fields.Item(i)) & "; value: '" & rs.Fields.Item(i) & "'")
End If
Next
rs.MoveNext
Loop
connerror:
If Err.Number <> 0 Then
Msg = "Error # " & str(Err.Number) & " was generated by " _
& Err.Source & Chr(13) & "Error Line: " & Erl & Chr(13) & Err.Description
MsgBox Msg, , "Error", Err.HelpFile, Err.HelpContext
End If
conn.Close
End Sub

Script fails with error code 80040E31

We have a VBScript that downloads chunks of data from an SAP Business Object database into so-called slices, which are basically .csv files. The script worked perfectly so far, I haven't really had to look into it at all. But the failure now is this:
The script file section this error refers to is the dbConn.Execute(strSQL) line in the below code (5th from below).
What I tried so far, was to add these commands but they don't seem to solve anything:
'dbConn.ConnectionTimeout = 100
'dbConn.CommandTimeout = 100
The script itself (not all of it, I'm not sure the rest is needed):
Sub subRunFilesInFolder(strFolder)
Dim FSO, objFolder, objFiles
Dim i, intTS, intTS_file_start, ts, tsKillBefore, TS_file_start, strModelName
Dim dbConn, RST, RST2, strSQL
Dim strVBSmodel
Dim blRunIt
'INIs
strModelName = "bo_vbs_runner_1.5 "
strConn = "DRIVER={SQL Server};SERVER=EUBASEURCIREP01;UID=ser_login;PWD=ser_login;DATABASE=ser"
strComputer = FunstrComputerName
strBORunner = "\\Eubaseurcirep01\reporting\DEVELOPMENT\BO\Automation\Models\BO_auto_run.xlsb"
'Sets
Set dbConn = CreateObject("ADODB.Connection")
Set RST = CreateObject("ADODB.RecordSet")
Set RST2 = CreateObject("ADODB.RecordSet")
Set WshShell = WScript.CreateObject("WScript.Shell")
Set FSO = Wscript.CreateObject("Scripting.FileSystemObject")
Set objFolder = FSO.GetFolder(strFolder)
Set objFiles = objFolder.Files
Set appExcel = CreateObject("Excel.Application")
'dbConn.ConnectionTimeout = 100
'dbConn.CommandTimeout = 100
strVBSmodel = strModelName & strComputer & " " & FunstrUserName & " " & funCurrProcessId & " " & FunGetProcessIDCurrentOfExcel(strComputer)
appExcel.Application.Visible = False
appExcel.Displayalerts = False
Set objBORunner = appExcel.Workbooks.Open(strBORunner)
dbConn.Open strConn
ts = FunGetServerNow(dbConn,RST)
tsKillBefore = DateAdd("N", -15, ts)
intTS = funTimeStampToInteger(FunGetServerNow(dbConn, RST))
'Get ReportDate
strSQL = "SELECT yyyymmdd FROM map.reportdate WHERE dtAct=cast(GETDATE() as DATE);"
RST.Open strSQL, dbConn
If RST.EOF Then
strReportDate="99991231"
Else
strReportDate=RST.fields(0).value
End If
RST.close
'Kill stucked excel and vbs processes
strSQL = "SELECT distinct * FROM [ser].[bo].[_log] WHERE [proc]='BO VBS' AND result_text='started' AND end_timestamp<" & funTimeStampToInteger(tsKillBefore) & _
" AND lower(model) like '% " & LCase(strComputer) & " %';"
RST.Open strSQL,dbConn
If RST.EOF Then 'Nothing to kill
Else
Do While Not RST.EOF
strOldVBS = split(RST.fields("model"), " ")(3)
strOldExcel = split(RST.fields("model"), " ")(4)
Call SubKillProcessIDOnstrComputer(strComputer, strOldVBS)
Call SubKillProcessIDOnstrComputer(strComputer, strOldExcel)
strSQL = "UPDATE [ser].[bo].[_log] SET result_text='stopped', end_timestamp='" & funTimeStampToInteger(FunGetServerNow(dbConn,RST2)) & "' " & _
"WHERE [proc]='BO VBS' AND result_text='started' AND model='" & RST.fields("model").value & "' AND parameters='" & _
RST.fields("parameters").value & "';"
dbConn.Execute(strSQL)
RST.MoveNext
Loop
End If
RST.close
To Decode 0x8004nnnn Errors
HResults with facility code 4 means the HResult contains OLE errors (0x0 =
to 0x1ff) while the rest of the range (0x200 onwards) is component =
specific errors so 20e from one component will have a different meaning =
to 20e from another component.
You are lucky as your component is telling you it's OLDB with it's error - TIMEOUT

Missing semicolon (;) at the end of SQL statement when insert data to ms access table

this is my code
dim straccess as string
Do While Not rso.EOF
30 straccess = "INSERT INTO [test] ([nik],[nama]) VALUES ('" & rso.Fields(0)
& "' ,'" & rso.Fields(1) & "' ) where [nama]= '" _
& rso.Fields(0) & "';"
cna.Execute straccess
Loop
got error on line 30 when insert data.
im type this code in vb6 n want to insert data from oracle database/table to msaccess database/table. i already hv connection to oracle table n ms access. And now I try to insert data into MS Access table based data in oracle table
my table name in ms access is TEST and my table name in empmasterepms.
this is my all code .
Dim vstr As String
Dim filename As String
Dim straccess As String
Option Explicit
Const ORACLEQUERY As String = "select empcode,empname from empmasterepms order by EMPNAME"
Dim cno As New ADODB.Connection
Dim cna As New ADODB.Connection
Dim rso As New ADODB.Recordset
Dim rsa As New ADODB.Recordset
Private Sub btnload_Click()
On Error GoTo Error_Handler
'-----------------Connection to Oracle
cno.Open "Provider=msdaora;Data Source=192.168.0.15:1521/EPMS;User Id=EPMS_TRXI;Password=epmse292014;"
rso.CursorType = adOpenStatic
rso.CursorLocation = adUseClient
rso.LockType = adLockOptimistic
rso.Open ORACLEQUERY, cno, , , adCmdText
Set dg1.DataSource = rso
------- connect to msaccess
cna.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & vstr
rso.MoveFirst
Do While Not rso.EOF
30 straccess = "Update test SET [nik] = '" & rso.Fields(0).Value & "' ,[nama] = '" & rso.Fields(1).Value & "' WHERE [nama] = '" & rso.Fields(1).Value & "';"
cna.Execute straccess
rso.MoveNext
Loop
MsgBox "Done"
cno.Close
Set cno = Nothing
Set cna = Nothing
Exit Sub
Error_Handler:
MsgBox Erl & ":" & Err.Number & ":" & Err.Description
Debug.Print (straccess)
end sub
Remove the Where statement:
30 straccess = "INSERT INTO [test] ([nik],[nama]) VALUES ('" & rso.Fields(0).Value & "','" & rso.Fields(1).Value & "');"

Resources