Can't execute SQL Server stored procedure in Access module - sql-server

In Access I created a form with Text1, List1, and Command1 elements.
The code for command button is:
Private Sub Command1_Click()
Dim con As ADODB.Connection
Dim cmd As ADODB.Command
Dim rs As ADODB.Recordset
Set con = New ADODB.Connection
Set cmd = New ADODB.Command
Set rs = New ADODB.Recordset
con.Open "Provider=sqloledb;Data Source=192.168.100.41,1433;Network Library=DBMSSOCN;Initial Catalog=xxx;User ID=xxx;Password=xxx;"
cmd.ActiveConnection = con
cmd.CommandTimeout = 0
cmd.Parameters.Append cmd.CreateParameter("#keyword", adVarChar, adParamInput, 100, Trim(Text1.Value))
cmd.CommandText = "stored_procedure"
Set rs = cmd.Execute(, , adCmdStoredProc)
If (rs.RecordCount <> 0) Then
Do While Not rs.EOF
Me.List1.AddItem (rs.Fields(0).Value & " | " & rs.Fields(1).Value & " | " & rs.Fields(2).Value)
rs.MoveNext
Loop
End If
rs.Close
Set rs = Nothing
Set cmd = Nothing
con.Close
Set con = Nothing
End Sub
When I try to run the code, nothing happens. No error. Seems like button is empty.
The SP works fine in SQL server.
The same button code, works fine in Excel form.
If I replace SP part with [rs.open "select * from table where keyword like.."] works fine
Thank you

You probably need to use a client side cursor, I would debug.print rs.RecordCount to check what it thinks are the returned records.
conn.cursorlocation=aduseclient

Related

Run SQL Server stored procedure from VBA

This is my stored procedure which works fine in SQL Server Management Studio.
exec GroupCommissions #GroupNumberEntry = '01142'
Should produce a table of data.
I'm trying to run it in vba using the following code:
Dim rs As ADODB.Recordset
Dim cnSQL As ADODB.Connection
Dim sqlcommand As ADODB.Command, prm As Object
Set cnSQL = New ADODB.Connection
cnSQL.Open "Provider=SQLOLEDB; Data Source=bddc1didw1;Initial Catalog=Actuarial; Trusted_connection=Yes; Integrated Security='SSPI'"
Set sqlcommand = New ADODB.Command
sqlcommand.ActiveConnection = cnSQL
sqlcommand.CommandType = adCmdStoredProc
sqlcommand.CommandText = "GroupCommissions"
Set prm = sqlcommand.CreateParameter("GroupNumberEntry", adParamInput)
sqlcommand.Parameters.Append prm
sqlcommand.Parameters("GroupNumberEntry").Value = "01142"
Set rs = New ADODB.Recordset
rs.CursorType = adOpenStatic
rs.LockType = adLockOptimistic
rs.Open sqlcommand
ActiveSheet.Range("a3").CopyFromRecordset rs
But it just returns blank and I can't work out what I'm doing wrong. Also is there a simpler way to do this?
As discussed below i've managed to fix the issue by adding SET NOCOUNT ON to the original stored procedure. My issue now is I want to do a second stored procedure in the same code but it only seems to work for one. They both work individually however. So either I have to reopen the connection or use 2 on the defined variables? Here is the code:
Dim rs As ADODB.Recordset
Dim cnSQL As ADODB.Connection
Dim sqlcommand As ADODB.Command, prm As Object, prm2 As Object
Set cnSQL = New ADODB.Connection
cnSQL.Open "Provider=SQLOLEDB; Data Source=bddc1didw1;Initial Catalog=Actuarial; Trusted_connection=Yes; Integrated Security='SSPI'"
Set sqlcommand = New ADODB.Command
sqlcommand.ActiveConnection = cnSQL
'groupdates
sqlcommand.CommandType = adCmdStoredProc
sqlcommand.CommandText = "GroupDate"
Set prm = sqlcommand.CreateParameter("GroupNumberEntry", adVarChar, adParamInput, 5)
Set prm2 = sqlcommand.CreateParameter("ValuationDateEntry", adDate, adParamInput)
sqlcommand.Parameters.Append prm
sqlcommand.Parameters.Append prm2
sqlcommand.Parameters("GroupNumberEntry").Value = "01132"
sqlcommand.Parameters("ValuationDateEntry").Value = "08-31-2019"
Set rs = New ADODB.Recordset
rs.CursorType = adOpenStatic
rs.LockType = adLockOptimistic
rs.Open sqlcommand
ActiveSheet.Range("a2").CopyFromRecordset rs
'GroupCommissions
sqlcommand.CommandType = adCmdStoredProc
sqlcommand.CommandText = "GroupCommissions"
Set prm = sqlcommand.CreateParameter("GroupNumberEntry", adVarChar, adParamInput, 5)
sqlcommand.Parameters.Append prm
sqlcommand.Parameters("GroupNumberEntry").Value = "01132"
Set rs = New ADODB.Recordset
rs.CursorType = adOpenStatic
rs.LockType = adLockOptimistic
rs.Open sqlcommand
ActiveSheet.Range("DB2").CopyFromRecordset rs
Try replacing that line with something like this:
Set prm = sqlcommand.CreateParameter("GroupNumberEntry", adVarChar, GroupNumberEntry, 255)
Set the field type and length according to how your proc is defined.
Your code looked OK to me so I copied it into Excel (2016...) and tried it. It gave me an error on that line but adding the additional parameter values to CreateParameter fixed the issue. shrug It shouldn't matter since those are optional parameters, unless there is something maybe at the provider level.
you can try just sending the SQL PROCEDURE straight through as a CALL function.
Take a look at this:
Public connDB As New ADODB.Connection
Public rs As New ADODB.Recordset
Public strSQL As String
Public strConnectionstring As String
Public strServer As String
Public strDBase As String
Public strUser As String
Public strPwd As String
Public PayrollDate As String
Sub WriteStoredProcedure()
PayrollDate = "2017/05/25"
Call ConnectDatabase
On Error GoTo errSP
strSQL = "EXEC spAgeRange '" & PayrollDate & "'"
connDB.Execute (strSQL)
Exit Sub
errSP:
MsgBox Err.Description
End Sub
Sub ConnectDatabase()
If connDB.State = 1 Then connDB.Close
On Error GoTo ErrConnect
strServer = "SERVERNAME" ‘The name or IP Address of the SQL Server
strDBase = "TestDB"
strUser = "" 'leave this blank for Windows authentication
strPwd = ""
If strPwd > "" Then
strConnectionstring = "DRIVER={SQL Server};Server=" & strServer & ";Database=" & strDBase & ";Uid=" & strUser & ";Pwd=" & strPwd & ";Connection Timeout=30;"
Else
strConnectionstring = "DRIVER={SQL Server};SERVER=" & strServer & ";Trusted_Connection=yes;DATABASE=" & strDBase 'Windows authentication
End If
connDB.ConnectionTimeout = 30
connDB.Open strConnectionstring
Exit Sub
ErrConnect:
MsgBox Err.Description
End Sub

VBA connecting to SQL Server

I am having trouble when connecting VBA to SQL Server:
Sub ConnectSQLServer()
Dim cmd As ADODB.Command
Dim conn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim strConn As String
Dim par As ADODB.Parameter
Dim strSQL As String
strConn = "DRIVER=SQL Server;SERVER=CHU-AS-0004;DATABASE=RTC_LaplaceD_DEV;Trusted_Connection=Yes;"
Set conn = New ADODB.Connection
conn.Open strConn
Set cmd = New ADODB.Command
cmd.CommandText = "dbo.Version"
cmd.CommandType = adCmdStoredProc
cmd.ActiveConnection = conn
rs.Open = "SELECT * FROM [dbo].[Version]"
cmd.Execute rs
Set conn = Nothing
Set cmd = Nothing
sConnString = ""
End Sub
I just want to select all values from the table named [dbo].[Version], but when I execute it, I get an error:
Compile error: Expected Function or Variable'
and the line with rs.Open is highlighted.
Would you help me to solve this problem?
Open is a method, and cannot be set with an =.
You probably want something like this:
rs.Open "SELECT * FROM [dbo].[Version]", conn
Once you have called Open, then you can iterate through the Recordset's rows using the EOF property and the MoveNext method:
Do While Not rs.EOF
Debug.Print rs.Fields(1)
'You could also use rs!FieldName, where FieldName is the name of a column
Loop
Change your code to the following:
Set cmd = New ADODB.Command
cmd.CommandText = "SELECT * FROM [dbo].[Version]"
cmd.CommandType = adCmdText
cmd.ActiveConnection = conn
Set rs = cmd.Execute
Do While Not rs.EOF
'do something with rs.Fields(0) '
rs.MoveNext
Loop
Set conn = Nothing
Set cmd = Nothing
rs.Fields is a zero based collection that means that the first field is 0, not 1.
You can get subsequent fields by rs.Fields(1), rs.Fields(2) etc. Or you can use Field names, with the syntax rs.Fields("MyFieldName").
Note when using a string command ("SELECT * FROM ..") the CommandType is adCmdText. The syntax for the Recordset is SET rs = cmd.Execute. Also you must invoke MoveNext in your loop, otherwise you get stuck in the loop!

Receiving an Error " The object you entered is not a valid record set property" access 2013 assigning record set to a form

I am using Access 2013 to upgrade an old application with sql 2012 back end. I have several Stored Procedures with parameters which i need to call and assigned to forms and reports.
The issue i am having is that i get the error "7965" every time i try to assigned the returned record set to the form
i am using the open event of the form and the following code
Private Sub Form_Open(Cancel As Integer)
Dim cmd1 As ADODB.Command
Dim recs1 As New ADODB.Recordset
Dim prm1 As ADODB.Parameter
Dim prm2 As ADODB.Parameter
Dim prm3 As ADODB.Parameter
Set cnn = CreateObject("ADODB.Connection")
cnn.ConnectionString = "DRIVER={SQL Server Native Client 11.0};SERVER=192.168.0.12;DATABASE=SavingsPlusCorp;Trusted_Connection=yes;"
cnn.Open cnn.ConnectionString
Set cmd1 = New ADODB.Command
Set cmd1.ActiveConnection = cnn
cmd1.CommandText = "dbo.iNVENSOLDSp"
cmd1.CommandType = adCmdStoredProc
Set prm1 = cmd1.CreateParameter("#branchid", adInteger, adParamInput, 2)
cmd1.Parameters.Append prm1
Set prm2 = cmd1.CreateParameter(" #Beginning_Date", adDate, adParamInput)
cmd1.Parameters.Append prm2
Set prm3 = cmd1.CreateParameter(" #Ending_Date", adDate, adParamInput)
cmd1.Parameters.Append prm3
Set prm4 = cmd1.CreateParameter("#vENDORID", adInteger, adParamInput, 2)
cmd1.Parameters.Append prm4
Set prm5 = cmd1.CreateParameter("#catID", adInteger, adParamInput, 2)
cmd1.Parameters.Append prm5
prm1.Value = Form_ReportGenerator.Branches
prm2.Value = Form_ReportGenerator.Begin_Date
prm3.Value = Form_ReportGenerator.Ending_Date
prm4.Value = Form_ReportGenerator.Vendors
prm5.Value = Form_ReportGenerator.Category
Set recs1 = CreateObject("ADOdB.recordset")
recs1.CursorType = adOpenKeyset
recs1.CursorLocation = adUseClient
'Set recs1 = cmd1.Execute
'recs1.Open
Set Me.Recordset = cmd1.Execute
I have also tried
set me.Recordset= recs1
with the same results
please help
The solution in the the thread identified as a possible is almost identical to my attempt
In fact I used it to build my attempt
I used the command. Execute and assigned it to my form
Set me.RecordSet = cmd1.execute
It is this line that returns the error
Is their an issue with the provider I am using to connect
I don't understand why it is not working
Please help
I had this problem, spent hours looking for it... turned to be right under my nose:
A function that had work perfectly well, repopulating an Access combo box from Mysql backed, suddenly gave this message after I changed adUseClient to adUseServer for barely relevant reasons. Here's the code (with thanks to Author: Christian Coppes)
Public Function fnADOComboboxSetRS(cmb As String, strSQL As String, strCallingForm As String, Optional StrCnnstring As String)
On Error GoTo fnADOComboboxSetRS_Error
Dim sourceDB As New clsAdoDBHelper
Dim RS1 As New ADODB.Recordset
If Len(StrCnnstring & vbNullString) = 0 Then
sourceDB.Connect CnString
Else
sourceDB.Connect StrCnnstring
End If
Set RS1 = sourceDB.OpenRecordset(strSQL, adUseClient)
Set Application.Forms(strCallingForm).Controls(cmb).Recordset = RS1
fnADOComboboxSetRS_Exit:
If Not RS1 Is Nothing Then
If RS1.State = adStateOpen Then RS1.Close
Set RS1 = Nothing
End If
Exit Function
fnADOComboboxSetRS_Error:
Select Case Err
Case Else
'fnErr "modODBC->fnADOComboboxSetRS", True
Resume fnADOComboboxSetRS_Exit
End Select
End Function
You need to call the Open method of an ADO.Recordset object.
To demonstrate this, first create a simple stored procedure in SQL Server.
USE AdventureWorks2016CTP3;
GO
CREATE PROCEDURE dbo.up_TestPerson
AS
SELECT BusinessEntityID, FirstName, LastName
FROM Person.Person;
Then create a Microsoft Access form with this code behind.
Private Sub Form_Open(Cancel As Integer)
Dim cnn As New ADODB.Connection
cnn.ConnectionString = "DRIVER={SQL Server Native Client 11.0};SERVER=V-SQL16-R;DATABASE=AdventureWorks2016CTP3;Trusted_Connection=yes;"
cnn.Open
Dim cmd1 As New ADODB.Command
Set cmd1.ActiveConnection = cnn
cmd1.CommandText = "dbo.up_TestPerson"
cmd1.CommandType = adCmdStoredProc
Dim rst As New ADODB.Recordset
rst.Open cmd1, , adOpenKeyset, adLockPessimistic
Set Me.Recordset = rst
End Sub
Open the form, and it displays the data.
To demonstrate using a parameter, create a stored procedure like this. (Same as the first stored procedure, except it has a parameter and a WHERE clause.)
CREATE PROCEDURE dbo.up_TestPerson2
(
#PersonType nchar(2)
)
AS
SELECT BusinessEntityID, FirstName, LastName
FROM Person.Person
WHERE PersonType = #PersonType;
Create another Access form with this code behind. (Same as the first form, except for the block where we create and configure the parameter.)
Private Sub Form_Open(Cancel As Integer)
Dim cnn As New ADODB.Connection
cnn.ConnectionString = "DRIVER={SQL Server Native Client 11.0};SERVER=V-SQL16-R;DATABASE=AdventureWorks2016CTP3;Trusted_Connection=yes;"
cnn.Open
Dim cmd1 As New ADODB.Command
Set cmd1.ActiveConnection = cnn
cmd1.CommandText = "dbo.up_TestPerson2"
cmd1.CommandType = adCmdStoredProc
' This is new
Dim prm1 As ADODB.Parameter
Set prm1 = cmd1.CreateParameter("#PersonType", adWChar, adParamInput, 2)
cmd1.Parameters.Append prm1
prm1.Value = "EM"
Dim rst As New ADODB.Recordset
rst.Open cmd1, , adOpenKeyset, adLockPessimistic
Set Me.Recordset = rst
End Sub
Open the form and it displays records matching the parameter.

Run time error '91' when using MSSql

I'm making a program in which I have to check some column values in another table before trying to save values in a different table.. both tables are in SQL.
I tried my best to do it myself but I get the error near the highlighted line.
rs.open(insert into testreport_tb1...
Private Sub Command1_Click()
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim BrdSrNo As String
Dim Result As Boolean
Dim machineName As String
machineName = Environ("computername")
' Ready objects for use.
Set cn = New ADODB.Connection
Set rs = New ADODB.Recordset
BrdSrNo = BoardSrNo.Text
Result = False
' Connect.
cn.Open "{Here I give the connection string}"
' Fetch a recordset.
rs.Open "select * from testreport_tb1 where board_SrNo = '" & BrdSrNo & "' order by test_DateTime desc", cn, adOpenStatic, adLockReadOnly
' Display value, and total recordcount.
MsgBox rs.Fields(3)
MsgBox rs.Fields(8)
'MsgBox rs.RecordCount
stage_Status = rs.Fields(3)
stage_Id = rs.Fields(8)
rs.Close
cn.Close
If stage_Status = "C" Then
If stage_Id = "True" Then
rs.Open "insert into testreport_tb1 values('" & BrdSrNo & "',3,GETDATE(),'" & Result & "',NULL,'" & machineName & "',' KO ','A','D')", cn, adOpenDynamic, adLockBatchOptimistic
MsgBox "saved"
End If
End If
' Close and release objects.
rs.Close
cn.Close
Set rs = Nothing
Set cn = Nothing
End Sub
As far as I remember, you can't use rs.Open when executing DML statements, (insert, update or delete), but only when you are executing select statements.
Also, you need to use ADODB.Command and set parameters instead of concatenating strings to create your insert statement, otherwise it's an open door for sql injection attacks.
It's been a very long time since the last time I've worked with ADODB, but your insert code should look something like this:
If stage_Status = "C" And stage_Id = "True" Then
Dim cmd as new ADODB.Command
cmd.CommandText = "insert into testreport_tb1 values(?, 3, GETDATE(), ?, NULL, ?, ' KO ', 'A', 'D')"
cmd.ActiveConnection = cn
Set param = cmd.CreateParameter(, adVarChar, adParamInput)
param.Value = BrdSrNo
cmd.Parameters.Append param
Set param = cmd.CreateParameter(, adVarChar, adParamInput)
param.Value = Result
cmd.Parameters.Append param
Set param = cmd.CreateParameter(, adVarChar, adParamInput)
param.Value = machineName
cmd.Parameters.Append param
cmd.Execute
MsgBox "saved"
End If
Note: Code was written directly here, and as I wrote, it's been a long time since I've used ADODB, so there might be mistakes in the code. However, this is the proper way of executing an insert statement with ADODB.

Bind Access form to the results from a Stored Procedure

I am trying to return the results of a stored procedure to a form. I have managed to iterate thru the results using an ADO recordset, but cannot bind the results to the form..
Here is the VBA code:
Private Sub RetrieveSiteInformation()
Dim cmd As New ADODB.Command
Dim cnn As New ADODB.Connection
Dim rs As ADODB.Recordset, f As ADODB.Field
With cnn
.Provider = "SQLOLEDB"
.ConnectionString =
"data source=UKFCSVR;initial catalog=ACACB;Trusted_Connection=Yes"
.Open
End With
Dim param1 As ADODB.Parameter
If Nz(txtSiteID_Search.Value, vbNullString) <> vbNullString Then
Set param1 = cmd.CreateParameter("#SiteID", adBigInt, adParamInput)
param1.Value = txtSiteID_Search.Value
cmd.Parameters.Append param1
End If
With cmd
.ActiveConnection = cnn
.CommandText = "spSiteInformation_Retrieve"
.CommandType = adCmdStoredProc
**' THIS FAILS**
Me.Recordset = .Execute
**' THIS LOOP WORKS FINE**
' Set rs = .Execute
' rs.MoveFirst
' For Each f In rs.Fields
' Debug.Print f.Name
' Next
' With rs
' Do While Not .EOF
' Debug.Print ![CompanyName] & " " & ![Postcode]
' .MoveNext
' Loop
' End With
End With
cnn.Close
End Sub
Okay, I have tested this example. It includes changes to suit my set-up which I have left in, rather than guessing at your set-up. Most of this is taken from http://support.microsoft.com/kb/281998/EN-US/
Dim cn As New ADODB.Connection
Dim cmd As New ADODB.Command
Dim param1 As New ADODB.Parameter
With cn
.Provider = "Microsoft.Access.OLEDB.10.0"
.Properties("Data Provider").Value = "SQLOLEDB"
.Properties("Data Source").Value = "Server"
.Properties("Integrated Security").Value = "SSPI"
.Properties("Initial Catalog").Value = "Test"
.Open
End With
txtSiteID_Search = 1
If Nz(txtSiteID_Search, vbNullString) <> vbNullString Then
Set param1 = cmd.CreateParameter("#SiteID", adBigInt, adParamInput)
param1.Value = txtSiteID_Search
cmd.Parameters.Append param1
End If
With cmd
.ActiveConnection = cn
.CommandText = "spSiteInformation_Retrieve"
.CommandType = adCmdStoredProc
Set Me.Recordset = .Execute
End With
Forget ADO. Create a passthru query in Access, with property ReturnsRecords = True.
Bind your form to that passthru query.
Using VBA, change the .SQL property of that QueryDef object, then open the form. You're done.
Set qry = CurrentDb.QueryDefs("myQryDef")
qry.SQL = "exec spMyStoredProc " & "'argument1'"
You need to use Set whenever you assign an object reference in VBA.
Change Me.Recordset = .Execute to Set Me.Recordset = .Execute.
Also, you probably need to open it with a supported cursor type. I don't think there's a way to change the cursor type if you use the Execute method on the Command object. You'll have to create the Recordset separately.
Set rs = New ADODB.Recordset
rs.Open cmd, , adOpenKeyset
Set Me.Recordset = rs

Resources