I'm trying to connect SQL Server to Access. I have the connection function in a module. I call this function in another module.
Here is the code in my module:
'Variabel voor SQL Server Connectie
Public SQLConnectie As ADODB.Connection
'Connecten met SQL Server
Public Function DBConn() As ADODB.Connection
If Not (SQLConnectie Is Nothing) Then
Set SQLConnectie = New ADODB.Connection
With SQLConnectie
.CommandTimeout = 15
.Mode = adModeReadWrite
.ConnectionString = "Provider=SQLNCLI11;Server=dafehvmvdsql3;Database=PROVOMotorenfabriek;Integrated Security=SSPI; Persist Security Info=False"
.Open
End With
End If
Set DBConn = SQLConnectie
Set SQLConnectie = Nothing
End Function
And below the code in the module which executes the stored procedure in SQL Server:
Call DBConn.Execute("EXEC spStoringToevoegen " & productielijnMW & ", " & Forms(Formnaam)!cbLijngedeelte & ".............etc
I get the error: Object variable or With block variable not set. Every answer I find says I need to put set in front of some variables but I can't find which one this should be.
Thanks in advance,
Adding this to sample parameters.
As I said my VBA is very rusty (and I find VBA particularly weird language to work with, add Access to that it sounds like a misery to me). It would be much easier if you used some other backend (and language as well). Anyway, here is a sample with parameters in VBA (Excel):
Sub Macro1()
Dim oRecordset1 As ADODB.Recordset
Dim oConnection As ADODB.Connection
Dim oCommand As ADODB.Command
Dim oParameter1 As ADODB.Parameter
Dim oParameter2 As ADODB.Parameter
Set oConnection = New ADODB.Connection
Set oCommand = New ADODB.Command
oConnection.ConnectionString = "Provider=SQLNCLI11.0;Data Source=.\SQLExpress;Trusted_connection=Yes"
oConnection.Open
oCommand.ActiveConnection = oConnection
oCommand.CommandType = 4
oCommand.CommandText = "Northwind.dbo.[CustomersSelectLike]"
Set oParameter1 = oCommand.CreateParameter("#country", 130, 1, -1) ' adWChar
oCommand.Parameters.Append oParameter1
oCommand.Parameters("#country").Value = "USA"
Set oParameter2 = oCommand.CreateParameter("#customer", 130, 1, -1)
oCommand.Parameters.Append oParameter2
oCommand.Parameters("#customer").Value = "%"
Set oRecordset = oCommand.Execute()
Sheet1.Range("A1").CopyFromRecordset (oRecordset)
End Sub
Related
I want to be able to execute a SQL Server stored procedure from MS Access VBA, in such a way that I can read (1) all the resulting result sets, not just the first one; and (2) any messages produced by PRINT statements or similar.
I have a test stored procedure with one input parameter, which produces 3 distinct result sets and about 90 messages. It calls several sub-stored procedures, I can EXEC it perfectly well from SSMS, but it isn’t clear (to me) how best to do it from Access VBA. I have tried the following so far:
DAO. Using SQL pass-through queries, I can get a lot of what I want in DAO, though it is a little clunky. It returns the first of the 3 result sets as a recordset, and by using the LogMessages attribute I can get a table (“Admin – NN”) containing the emitted messages.
ADO. Using Connection and Command objects, I can obtain a single recordset representing the first result set from the stored procedure. However, I can’t seem to persuade it to produce anything but a forward-only recordset. Regarding messages, at one point, all of them (at least, the first 127 of the approx. 150 I expected) were going into the connection’s Errors collection (!), but when I cut the number down to about 90, none of them appeared anywhere at all that I could find.
What I really want, as I said at first, is the output from all result sets, plus the messages. Is this possible?
Here is a listing of the routine I am currently using for executing a stored procedure :
Function ExecuteStoredProcedureADO(SPName As String, Connect As String, ReturnsRecords As Boolean, _
ParamArray Params() As Variant) As ADODB.Recordset
' v1.0 2018/06/26
' execute stored procedure SPName on a SQL Server database specified by the string in Connect
Dim strErr As String
Dim i As Integer
Dim lngRecsAffected As Long
Dim cnn As ADODB.Connection
Dim cmd As ADODB.Command
Dim errCurr As ADODB.Error
Dim rst As ADODB.Recordset
On Error GoTo Catch
Set ExecuteStoredProcedureADO = Nothing
Set cnn = New ADODB.Connection
cnn.Errors.Clear
cnn.mode = adModeRead
cnn.CommandTimeout = 300
cnn.Open Connect
Set cmd = New ADODB.Command
With cmd
.ActiveConnection = cnn
.CommandText = SPName
.CommandType = adCmdStoredProc
For i = 0 To UBound(Params) Step 4
.Parameters.Append .CreateParameter(Params(i), Params(i + 1), adParamInput, Params(i + 2), Params(i + 3))
Next i
Set rst = New ADODB.Recordset
rst.CursorType = adOpenStatic
If ReturnsRecords Then
'''Set rst = .Execute(lngRecsAffected)
rst.Open cmd, , adOpenStatic, adLockReadOnly
Else
Set rst = .Execute(, , adExecuteNoRecords)
End If
End With
If ReturnsRecords Then Set ExecuteStoredProcedureADO = rst
Final:
On Error Resume Next
If Len(strErr) > 0 Then Call AppendMsg(strErr)
Set rst = Nothing
Set cmd = Nothing
Exit Function
Catch:
If cnn.Errors.Count > 0 Then
With cnn
For Each errCurr In cnn.Errors
strErr = strErr & "Error " & errCurr.Number & ": " & errCurr.Description _
& " (" & errCurr.Source & ")" & vbCrLf
Next errCurr
strErr = Left(strErr, Len(strErr) - 2) ' truncate final CRLF
End With
Else
strErr = "Error " & Err.Number & ": " & Err.Description & " (" & Err.Source & ")"
End If
MsgBox strErr, vbOKOnly, gtitle
Resume Final
End Function
Addendum: Regarding the multiple result sets, I am hoping that http://msdn.microsoft.com/en-us/library/ms677569%28VS.85%29.aspx
will be of some help.
To shamelessly piggy-back off of #Erik, you want to create a new class that will handle your processing. Something like cProcedureHandler. Within this class, you need to declare an ADODB.Connection object using the WithEvents keyword:
Dim WithEvents cn As ADODB.Connection
Then, you need to write a InfoMessage event handler that will take care of the multiple print statements. Information about the InfoMessage event can be found here, and using the connection's Errors collection can be found here. So you'll end up with something like this:
Private Sub cn_InfoMessage(ByVal pError As ADODB.Error, adStatus As ADODB.EventStatusEnum, ByVal pConnection As ADODB.Connection)
Dim err As ADODB.Error
Debug.Print cn.Errors.Count & " errors"
For Each err In cn.Errors
' handle each error/message the way you need to.
Debug.Print err.Description
Next err
End Sub
Since you've taken care of the code to handle multiple messages, now you just need to handle the multiple recordsets, which is explained pretty well in the link you provided. One thing I noticed was that the example link used rs is nothing as the check for when there were no more recordsets, which didn't work for me. I had to use the rs State property. So I ended up with this:
Public Sub testProcedure()
Dim cmd As ADODB.Command
Dim rs As ADODB.Recordset
Dim recordSetIndex As Integer
Set cn = modData.getConnection
Set cmd = New ADODB.Command
cmd.ActiveConnection = cn
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "dbo.sp_foo"
Set rs = cmd.Execute
recordSetIndex = 1
Do Until rs.State = ObjectStateEnum.adStateClosed
Debug.Print "contents of rs #" & recordIndex
Do Until rs.EOF
Debug.Print rs.Fields(0) & rs.Fields(1)
rs.MoveNext
Loop
Set rs = rs.NextRecordset
recordSetIndex = recordIndex + 1
Loop
cn.Close
Set rs = Nothing
Set cn = Nothing
Set cmd = Nothing
End Sub
Then, when you're ready to run your SP from VBA, just do something like this:
set obj = new cProcedureHandler
obj.testFooProcedure
Another thing (you probably have already done this): Make sure your actual stored procedure in SQL Server sets nocount on.
I'm trying to run a stored procedure on VBA using the following VBA code:
Please can someone advise: I get the error at "rs.Open".
Sub connection()
Dim Conn As ADODB.connection
Dim ADODBCmd As ADODB.Command
Dim rs As ADODB.Recordset
Dim i As Integer
Dim constring As String
Dim location As String 'the server
Dim password As String
location = "10.103.98.18"
password = "password"
constring = "Provider=SQLOLEDB; Network Library=DBMSSOCN;Data Source=" & location & ";Command Timeout=0;Connection Timeout=0;Packet Size=4096; Initial Catalog=ElColibri; User ID=Analyst1; Password=password;"
Set Conn = New ADODB.connection
Conn.connectionString = constring
'On Error GoTo ConnectionError
Conn.Open
'loginstatus = False
'Exit Sub
'errorhandl0
'ConnectionError:
'MsgBox "Not possible to log in. Have you entered the correct password?"
'open recordset
Set ADODBCmd = New ADODB.Command
ADODBCmd.ActiveConnection = Conn
ADODBCmd.CommandTimeout = 1200
ADODBCmd.CommandText = ["ukrmc.dbo.FridayCommentary"]
ADODBCmd.CommandType = 4 'adCmdStoredProc
ADODBCmd.Execute
Set rs = New ADODB.Recordset
rs.ActiveConnection = Conn
rs.Open
Conn.Close
Set Conn = Nothing
Set ADODBCmd = Nothing
'Paste to spreadsheet
ThisWorkbook.Worksheets("macrotest").Range("a2").CopyFromRecordset
'Set rs = conn.Execute(Query)
rs.Close
Set rs = Nothing
End Sub
To me the code makes logical sense to me so I am not sure what the error means. Because to me, I have set text for the command object.
You are not connecting the recordset to your command. Assuming that your stored procedure issues a SELECT, change your code to
Set rs = ADODBCmd.Execute
thisWorkbook.Worksheets("macrotest").Range("a2").CopyFromRecordset rs
The Execute-Method will return a Recordset as result, no need to create one by yourself.
Or you should add the command object to the open operation
rs.Open ADODBCmd
I am wanting to query a SQL Server Table and store the results from that query in an array. I am only returning a Distinct() from one field so it should be pretty straight forward. My syntax produces the error
Invalid Qualifier
On this line of code Set r = conn.Execute and it highlights the word conn How should I re-write this syntax to still use ADO but be able to successfully run this procedure?
Public Function ReturnData()
Dim c As ADODB.Connection
Dim r As ADODB.Recordset
Dim f As ADODB.Field
Dim conn As String
Dim arrResults() As Variant
Set c = New ADODB.Connection
With c
.Provider = "sqloledb.1"
With .Properties
.Item("Data Source") = "ServerName"
.Item("Initial Catalog") = "Database"
.Item("PassWord") = "password"
.Item("User ID") = "user"
End With
.Open
Set r = conn.Execute("SELECT Distinct(Name) from registered where cancelled IS NULL;")
i = 0
r.MoveFirst
Do Until rst.EOF
arrResults(i) = rst.Fields(0)
i = i + 1
Loop
rst.Close
Set rst = Nothing
c.Close
End Function
Another way to get a recordset into an array is to use Split and Recordset.GetString. It avoids the loop anyway. Here's an example.
Public Sub RsToArray()
Dim adoCon As ADODB.Connection
Dim adoRs As ADODB.Recordset
Dim vaLocations As Variant
Set adoCon = New ADODB.Connection
adoCon.Open sConn
Set adoRs = adoCon.Execute("SELECT DISTINCT LocationName FROM Locations")
vaLocations = Split(adoRs.GetString, vbCr)
Debug.Print Join(vaLocations, "|")
adoRs.Close
adoCon.Close
Set adoRs = Nothing
Set adoCon = Nothing
End Sub
you've got conn is a string there, c is a connection - can you do c.execute
try
Set r = c.Execute(...
I'm not sure if you need a command object, if you do, then see
https://msdn.microsoft.com/en-us/library/ms675065%28v=vs.85%29.aspx
to see how to make a command for your connection and execute it
Anyhow, at the moment you are trying to 'execute' on a string - string is a primitive type and does not execute on the DB - I think you just mixed c and conn up - let us know how it goes
I am trying to execute a SQL Server stored procedure from vb.net 2008. But I get the error
Procedure or function 'Sp_Messages_Display' expects parameter '#MsgSno', which was not supplied.
Here is my code
Public Function Load(ByVal CnnStr As String, ByVal MsgSno As Long, ByVal Msg_Status As eMsgStatus) As ADODB.Recordset
Dim Cnn As ADODB.Connection
Dim Com As ADODB.Command
Cnn = New ADODB.Connection
Cnn.CursorLocation = ADODB.CursorLocationEnum.adUseClient
Cnn.ConnectionString = CnnStr
Cnn.Open()
Com = New ADODB.Command
Com.ActiveConnection = Cnn
With Com
.CommandType = ADODB.CommandTypeEnum.adCmdStoredProc
.CommandText = "Sp_Messages_Display"
.CreateParameter("#MsgSno", ADODB.DataTypeEnum.adBigInt, ADODB.ParameterDirectionEnum.adParamInput, 4, MsgSno)
.CreateParameter("#Msg_Status", ADODB.DataTypeEnum.adSmallInt, ADODB.ParameterDirectionEnum.adParamInput, 4, Msg_Status)
Load = .Execute(RecordsAffected)
SqlError = Err.Description
End With
If Not Load.EOF Then
With Me
.MsgSno = Load.Fields("MsgSno").Value
End With
End If
Com.ActiveConnection = Nothing
Cnn = Nothing
End Function
Please help me where I am wrong. Thanks in advance
You need to add parameters to the Command, the CreateParameter only creates a new instance without adding it to the collection of the Command:
With Com
CommandType = ADODB.CommandTypeEnum.adCmdStoredProc
.CommandText = "Sp_Messages_Display"
.Parameters.Add("#MsgSno", ADODB.DataTypeEnum.adBigInt, ADODB.ParameterDirectionEnum.adParamInput, 4, MsgSno)
.Parameters.Add("#Msg_Status", ADODB.DataTypeEnum.adSmallInt, ADODB.ParameterDirectionEnum.adParamInput, 4, Msg_Status)
Load = .Execute(RecordsAffected)
SqlError = Err.Description
End With
I now believe you are not using VB.NET, but VB, in that case this is the way to go from MSDN:
ccmd.parameters.Append ccmd.CreateParameter(, adInteger, adParamReturnValue, , NULL) ' return value
ccmd.parameters.Append ccmd.CreateParameter("InParam", adVarChar, adParamInput, 20, "hello world") ' input parameter
ccmd.parameters.Append ccmd.CreateParameter("OutParam", adVarChar, adParamOuput, 20, NULL) ' output parameter
From the documentation to CreateParameter:
This method does not automatically append the Parameter object to the Parameters collection of a Command object.
You need to add the parameter you have created to the collection.
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.