I am attempting to get an output variable (the new identity column) from a stored procedure in SQL Server 2008 after executing the procedure from Access 2013 VBA. I don't fully understand all the adodb stuff, and I've tried a number of things from different articles to no avail. Here's where I am with it now...
Stored procedure:
PROCEDURE [proc_NewClient]
#Type INT,
#PhoneIntakeID INT,
#ClientID INT = NULL,
#NewPSID INT = null OUTPUT (2 possible ways to call the proc, one does not produce an output variable)
INSERT INTO tblClientDetails (ClientID, PhoneIntakeID, Client_Status)
VALUES (#ClientID, #PhoneIntakeID, 'Applicant')
DECLARE #NewClientDetailID int
SELECT #NewClientDetailID = SCOPE_IDENTITY()
INSERT INTO tblPS_Psychosocial (ClientDetailID, Client)
VALUES (#NewClientDetailID, #ClientID)
SELECT #NewPSID = SCOPE_IDENTITY()
INSERT INTO tblPS_AbuseHistory (PsychosocialID)
VALUES (#NewPSID)
INSERT INTO tblPS_FamilyHistory(PsychosocialID) VALUES (#NewPSID)
INSERT INTO tblPS_FinancialHistory (PsychosocialID) VALUES (#NewPSID)
INSERT INTO tblPS_LegalHistory (PsychosocialID) VALUES (#NewPSID)
INSERT INTO tblPS_MedicalHistory (PsychosocialID) VALUES (#NewPSID)
INSERT INTO tblPS_PsychiatricHistory (PsychosocialID) VALUES (#NewPSID)
INSERT INTO tblPS_SocialHistory (PsychosocialID) VALUES (#NewPSID)
INSERT INTO tblPS_SpiritualHistory (PsychosocialID) VALUES (#NewPSID)
INSERT INTO tblPS_SubstanceHistory (PsychosocialID) VALUES (#NewPSID)
INSERT INTO tblVocAssessment(ClientDetailID) VALUES (#NewClientDetailID)
And from the form I've got:
Dim cnn As ADODB.Connection
Dim cmd As New ADODB.Command, rs As New ADODB.Recordset, param1 As New ADODB.Parameter, param2 As New ADODB.Parameter, param3 As New ADODB.Parameter, param4 As New ADODB.Parameter
Set cnn = New ADODB.Connection
cnn.ConnectionString = "DRIVER=SQL Server;SERVER=SRV-DB01;DATABASE=TWHClientMgmt;Trusted_Connection=Yes"
cnn.Open cnn.ConnectionString
Set cmd = New ADODB.Command
cmd.ActiveConnection = cnn
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "[THEWOMENSHOME\jboyd].proc_NewClient"
Set param1 = cmd.CreateParameter("#Type", adinteger, adparamInput, , 2)
cmd.Parameters.Append param1
Set param2 = cmd.CreateParameter("#PhoneIntakeID", adinteger, adparamInput, , Me.PhoneIntakeID)
cmd.Parameters.Append param2
Set param3 = cmd.CreateParameter("#ClientID", adinteger, adparamInput, , intNewID)
cmd.Parameters.Append param3
Set param4 = cmd.CreateParameter("#NewPSID", adinteger, adParamOutput)
cmd.Parameters.Append param4
rs.open cmd
To this point the code works, the new records are generated, etc. When I run the stored procedure from SQL Server it returns the correct identity column number, but I've tried multiple ways to reference the output in VBA and always end up coming up with a null. How do I reference it here correctly?
To retrieve the value of a stored procedure's OUTPUT parameter you simply .Execute the ADODB.Command and then retrieve the .Value of the corresponding ADODB.Parameter, like so:
cmd.Execute
' retrieve and display the returned OUTPUT parameter value
Debug.Print cmd.Parameters("#NewPSID").Value
Simple DAO solution calling stored procedure:
Public Function RunSqlQuery(q As String) As Variant
Dim cdb As DAO.Database
Dim qdf As DAO.QueryDef
Dim rs As Recordset
Set cdb = CurrentDb
Set qdf = cdb.CreateQueryDef("")
qdf.Connect = cdb.TableDefs("dbo_Setup").Connect ' your attached table
qdf.SQL = q
qdf.ReturnsRecords = True
Set rs = qdf.OpenRecordset()
RunSqlQuery = rs.Fields(0) ' you also can output more than one parameter from a stored procedure as fields
rs.Close
Set rs = Nothing
Set qdf = Nothing
Set cdb = Nothing
End Function
Now, call the function, define a query the same way you would do at the SQL server:
? RunSQLQuery("DECLARE #param1 varchar(16); exec proc_MyStoredProcedure #param1 OUTPUT; SELECT #param1")
Related
I would appreciate any help on this problem that has me stumped:
I am attempting to execute a SQL Server 2008 stored procedure from Access 365 VBA and keep faulting out with "Multiple-step OLE DB operation generated errors".
This fault began when I changed a column in the target table from int datatype to decimal(3,1). (I now need to be able to store a single digit to the right of the decimal).
For troubleshooting/ testing, I stripped the stored procedure down to update this column only. (OCR_Freq is the update column, OcrxId is the record id).
I have verified/tried:
1) The table column is set to decimal(3,1).
2) The data type in the stored procedure variable is decimal(3,1).
3) The stored procedure executes without issue from SQL Server
Management Studio.
4) Changing the column datatype to decimal(18,4) had no effect.
4) The vba code below executes without issue if the DataType is
adInteger.
5) I use this code to execute a number of other stored procedures
without issue.
'VBA CODE:
Dim Comm As ADODB.Command
Dim lngRecordsAffected As Long
Dim param1 As New ADODB.Parameter
Dim param2 As New ADODB.Parameter
'************************************************
Dim ocrxid As Long
Dim OCR_Freq As Variant
Dim x As Single
'testing the formatting
x = 7.2 'doesn't work
'OCR_Freq = Round(x, 1) 'doesn't work
'OCR_Freq = CDec(x) 'doesn't work
'OCR_Freq = Round(OCR_Freq, 1) 'doesn't work
OCR_Freq = CDec(Format(x, "00.0")) 'doesn't work
'connection stuff
If con.State = adStateClosed Then
con.ConnectionString = conConnection
con.Open
End If
Set Comm = New ADODB.Command
With Comm
.ActiveConnection = con
.CommandType = adCmdStoredProc
.CommandText = "up_EOCR_TEST"
'--- ADD PARAMETERS --------------------------------
'OCR_Freq decimal(3,1)
Set param1 = Comm.CreateParameter("#OCR_Freq", adDecimal,
adParamInput, , OCR_Freq)
Comm.Parameters.Append param1
'test record id
Set param2 = Comm.CreateParameter("#OcrxId", adInteger,
adParamInput, , 8053)
Comm.Parameters.Append param2
.Execute lngRecordsAffected
End With
'END VBA CODE
//SQL Stored Procedure:
#OCR_Freq decimal(3,1) = null,
#OcrxId int = null
as
begin
UPDATE dbo.OCRX SET OCR_Freq=#OCR_Freq WHERE OCR_ID=#OcrxId;
END
The error I am getting is "Multiple-step OLE DB operation generated errors"
The above leads me to conclude that I am not properly "preparing" the value in vba for the stored procedure execution- adDecimal is not happy with my variable...
but I am at loss as how to move forward. Any help would be appreciated.
Well, the solution was staring me in the face- I forgot to set the NumericScale and precision on param1 before appending it:
'VBA CODE CORRECTED:
Dim Comm As ADODB.Command
Dim lngRecordsAffected As Long
Dim param1 As New ADODB.Parameter
Dim param2 As New ADODB.Parameter
'************************************************
Dim ocrxid As Long
Dim OCR_Freq As Variant
Dim x As Single
'testing the formatting
x = 7.5
OCR_Freq = x
'connection stuff
If con.State = adStateClosed Then
con.ConnectionString = conConnection
con.Open
End If
Set Comm = New ADODB.Command
With Comm
.ActiveConnection = con
.CommandType = adCmdStoredProc
.CommandText = "up_EOCR_TEST"
'--- ADD PARAMETERS ---------------------------------------------------
'OCR_Freq decimal(3,1)
Set param1 = Comm.CreateParameter("#OCR_Freq", adDecimal, adParamInput, ,
OCR_Freq)
param1.NumericScale = 1
param1.Precision = 3
Comm.Parameters.Append param1
Set param2 = Comm.CreateParameter("#OcrxId", adInteger, adParamInput, ,
8053)
Comm.Parameters.Append param2
.Execute lngRecordsAffected
End With
I'm trying to use the parameterizartion to prevent SQL injection in one of the textbox in the HMI I working with.
Have looked a lot for a solution what I gathered is depending on what SQL syntax there is I can use either ? or # to tell the system that is parameter but both of them are throwing an error.
Dim DBCommand
Dim DBRecordSet
Dim Connection
Dim sqlString
Set DBRecordSet = CreateObject("ADODB.Recordset")
Set DBCommand = CreateObject("ADODB.Command")
Set Connection = GetDBConnection("Test")
sqlString = "Insert into [WorkCommentLog] (Worklog_WorkID, Comment,
InsertTime, WrittenBy) values" &_
"('"& WorkID &"' , #Comm , GetDate() , '" & User.Value &"');"
DBCommand.Parameters.Append DBCommand.CreateParameter ("#Comm",
adVarChar, adParamInput, 255, WinCC_Comment.Value)
DBCommand.CommandText = sqlString
DBCommand.Execute(adExecuteNoRecords)
Connection.Close
Dim DBCommand
Dim DBRecordSet
Dim Connection
Dim sqlString
Set DBRecordSet = CreateObject("ADODB.Recordset")
Set DBCommand = CreateObject("ADODB.Command")
Set Connection = GetDBConnection("Test")
sqlString = "Insert into [WorkCommentLog] (Worklog_WorkID, Comment, InsertTime, WrittenBy) values" &_
"('"& WorkID &"' , ? , GetDate() , '" & User.Value &"');"
DBCommand.Parameters.Append DBCommand.CreateParameter ("Comment", adVarChar, adParamInput, 255, WinCC_Comment.Value)
DBCommand.CommandText = sqlString
DBCommand.Execute(adExecuteNoRecords)
Connection.Close
The first code snippet throws this error:
Must declare the scalar variable "#Com"
while the second code snippet throws this error:
No Value given for one or more required parameters
I have found that executing a parametrized query using VBScript like so has always worked for me:
Set command = CreateObject("ADODB.Command")
Set command.ActiveConnection = Connection
command.CommandText = "sp0001_ExampleStoredProcedure" ' The name of the stored procedure in my database that has the parametrized query.
command.CommandType = 4
command.Parameters("#Parameter1") = "parameterValue"
command.Parameters("#Parameter2") = "parameterValue"
command.Execute
Note that this example is executing a parametrized stored procedure in my database.
You could try writing your insert query into a stored procedure in your database instead of hard-coding your query in the VBScript file.
I need some help solving this issue. I'm a VB novice, by the way. I currently have a stored procedure that accepts 3 parameters and when executed returns a temp table. I tested my procedure in SQL and it's working as expected.
I'm using an Access form as my front-end. It is to accept the 3 parameters via 3 text box controls and then executes my procedure 'on click' (User clicks the search button to execute and fire up SQL). The code below accomplishes this, up until it's time to display my recordsets in a table. I'm stuck on how to display my results from my procedure in a table by utlizing ADO properties I'm ok with either displaying the recordset in a datasheet form or inserting them into a table.
The code seems to choke up at this line, where I'm attempting to view my recordset:
rs.Open cmd
Access VB Code
Private Sub cmdExecuteQuery_Click()
Dim conn As ADODB.Connection
Dim cmd As ADODB.Command
Dim rs As ADODB.Recordset
Dim accessionno As String
Set conn = New ADODB.Connection
Set rs = New ADODB.Recordset
conn.ConnectionString = "Driver={SQL Server};Server=***;Database=***;Uid=****;Pwd=***;"
conn.Open
Set cmd = New ADODB.Command
cmd.ActiveConnection = conn
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "dbo.NameofStoredProcedure"
cmd.Parameters.Append cmd.CreateParameter("#worksheetno", adVarChar,
adParamInput, 10, Forms!RepeatForm!txtEnterWrkSheetno)
cmd.Parameters.Append cmd.CreateParameter("#name", adVarChar,
adParamInput, 10, Forms!RepeatForm!txtEnterName)
cmd.Parameters.Append cmd.CreateParameter("#year", adVarChar,
adParamInput, 4, Forms!RepeatForm!txtEnterYear)
With rs
.ActiveConnection = conn
.CursorType = adOpenForwardOnly
.CursorLocation = adUseServer
End With
Set rs = cmd.Execute()
DoCmd.OpenForm "frmRepeats", acViewNormal
rs.Open cmd
rs.Close
conn.Close
Set rs = Nothing
Set cmd = Nothing
Set conn = Nothing
End Sub
SQL
CREATE PROCEDURE [dbo].[NameofStoredProcedure] #worksheetno varchar(10),
#name varchar(10), #year varchar(4)
AS
BEGIN
CREATE TABLE #Temp (accessionno varchar (100),
No varchar (100),
worksheetno varchar (10),
name varchar(100),
location varchar (10),
Result varchar (100),
year varchar (4))
INSERT INTO #Temp
SELECT DISTINCT
a.accessionno,
e.name + substring(a.Year, 3,2) + '-' + convert(varchar(10),
c.SampleTestNum) AS No,
a.worksheetno,
b.name,
c.platetext AS Location,
d.finalcomment AS Result,
a.Year
FROM
tb_sample a (nolock), tb_patient b (nolock), tb_plate c (nolock),
tb_finalresult d (nolock), tb_testcode e (nolock)
WHERE
a.sample_id = b.sample_id
and a.sample_id = c.sample_id
and a.sample_id = d.sample_id
and a.test_id = e.test_id
and finalcomment like '%1061%'
and worksheetno = #worksheetno
and e.name = #name
and a.year = #year
ORDER BY No
END
select distinct * from #Temp
drop table #Temp
GO
I am using MS Access VBA to call a stored procedure with paramters passed from Access. I am having issues passing my date variables to the SQL Server Stored procedure:
VBA:
Dim zsql, asql, bsql, gsql As String
Dim searchDeal, searchReviewed As String
Dim searchDate, searchFile As Date
Dim searchType As String
Dim user As String
Dim qdfNew As DAO.QueryDef
Dim myRecordset6 As DAO.Recordset
Dim myDatabase6 As DAO.Database
Dim mycheckRs As DAO.Recordset
DoCmd.SetWarnings False
searchDeal = Me.cboDeal.Value
searchDate = Me.cboStDate.Value
searchFile = Me.cboFile.Value
user = GetUser()
Dim dbconn As New ADODB.Connection
Dim cmd As New ADODB.Command
Dim rs As New ADODB.Recordset
Dim param As New ADODB.Parameter
'' Connect to Data Source - Securities DB - SQL Server
Set dbconn = New ADODB.Connection
dbconn.ConnectionString = "driver=SQL Server;server=R7SQL1;database=SecuritiesDB;trusted_connection=YES"
dbconn.Open dbconn.ConnectionString
Set cmd = New ADODB.Command
cmd.ActiveConnection = dbconn
'' Set CommandText equal to the stored procedure name (spStatementCheck)
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "spAppendActivity"
''cmd.NamedParameters = True 'paramStatementCheck'
cmd.Parameters.Append _
cmd.CreateParameter("#SPstrNGN", adVarChar, adParamInput, 25, searchDeal)
cmd.Parameters.Append _
cmd.CreateParameter("#SPuser", adVarChar, adParamInput, 100, user)
cmd.Parameters.Append _
cmd.CreateParameter("#SPdDateActivity", adDBTimeStamp, adParamInput, 10, searchDate) <--ISSUE
cmd.Parameters.Append _
cmd.CreateParameter("#SPdDateFile", adDBTimeStamp, adParamInput, 10, searchFile) <--ISSUE
--Date format that I am passing should be MM/DD/YYYY
rs.CursorType = adOpenDynamic
rs.CursorLocation = adUseClient
rs.LockType = adLockOptimistic
rs.Open cmd
SQL:
ALTER PROCEDURE [dbo].[spAppendActivity]
#SPsearchDeal as nvarchar(25),
#SPsearchDate as datetime,
#SPsearchFile as datetime,
#SPuser as nvarchar(100)
AS
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
delete from tbl_Activity_Losses;
INSERT into tbl_Activity_Losses ([Date], NGN_Short, FileDate)
Select [Date], NGN_Short, Filedate
from tbl_Master_Rec
where tbl_Master_Rec.[Date] = #SPsearchDate <--Conversion Issue
and tbl_Master_Rec.FileDate = #SPsearchFile <--Conversion Issue
and tbl_Master_Rec.NGN_Short like '%' + #SPsearchDeal + '%'
I get the following error message when the Date is passed using the adDBTimeStamp "[Microsoft][ODBC SQL Server Driver] Conversion failed when converting date and/or time from character string."
I have also tried passing the date as adDBDate and get the error "[Microsoft][ODBC SQL Server Driver] Optional Feature Not Implemented. "
Please let me know if you need more information on the issue I am having
Please note that you will need to construct the datetime string in this format:
adDBDate
Indicates a date value (yyyymmdd) (DBTYPE_DBDATE).
adDBTimeStamp
Indicates a date/time stamp (yyyymmddhhmmss plus a fraction in billionths) (DBTYPE_DBTIMESTAMP).
adDBDate and adDBTimeStamp
I have a SQL Server 2008 stored procedure that updates values in a table. I would like to have the stored procedure return an integer value indicating that the update was successful (return 0) or not (returns error number). What would be the best way to accomplish this via ADO and VBA? Here some of my code in simplified form that performs the update ... I am just not sure how to get back the return value of the stored procedure
Public Function DoUpdate(employeeID as integer, firstName as string, lastname as string) as integer
Dim cnn As ADODB.Connection
Dim cmd As ADODB.Command
Dim activeConnectionString As String
activeConnectionString = GetActiveConnectionString()
Set cnn = New ADODB.Connection
cnn.ConnectionString = activeConnectionString
cnn.CursorLocation = adUseClient
cnn.Open
Set cmd = New ADODB.Command
cmd.ActiveConnection = cnn
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "uspUpdateEmployeeName"
cmd.NamedParameters = True
cmd.Parameters("#EmployeeID").Value = employeeID
cmd.Parameters("#FirstName").Value = firstName
cmd.Parameters("#LastName").Value = lastName
cmd.Execute
'Unsure of how to get back return value here
'DoUpdate = returnValue
Set cnn = Nothing
End Function
Note: The return_value must be the first parameter!
Order matters.
I was getting errors stating that my query "had too many arguments" when I had specified my return_value parameter last, instead of first.
The parameters' ordering was the cause of my error.
If you use
Dim lngRecs As Long
cmd.Execute lngRecs
lngRecs should contain records affected.
I seem to remember that you need to supply an extra parameter with the type 'adParamReturnValue' like this:
Dim lRetVal as Long
Set cmd = New ADODB.Command
cmd.Parameters.Append .CreateParameter("returnvalue", adInteger, adParamReturnValue)
cmd.Execute
'Now check the return value of the procedure
lRetVal = cmd.Parameters("returnvalue")
If lRetVal > 0 then
Several ways are possible to get values back using VBA:
Recordset
Count of records affected (only for Insert/Update/Delete otherwise -1)
Output parameter
Return value
My code demonstrates all four. Here is a stored procedure that returns a value:
Create PROCEDURE CheckExpedite
#InputX varchar(10),
#InputY int,
#HasExpedite int out
AS
BEGIN
Select #HasExpedite = 9 from <Table>
where Column2 = #InputX and Column3 = #InputY
If #HasExpedite = 9
Return 2
Else
Return 3
End
Here is the sub I use in Excel VBA. You'll need reference to Microsoft ActiveX Data Objects 2.8 Library.
Sub CheckValue()
Dim InputX As String: InputX = "6000"
Dim InputY As Integer: InputY = 2014
'open connnection
Dim ACon As New Connection
'ACon.Open ("Provider=SQLOLEDB;Data Source=<SqlServer>;" & _
' "Initial Catalog=<Table>;Integrated Security=SSPI")
'set command
Dim ACmd As New Command
Set ACmd.ActiveConnection = ACon
ACmd.CommandText = "CheckExpedite"
ACmd.CommandType = adCmdStoredProc
'Return value must be first parameter else you'll get error from too many parameters
'Procedure or function "Name" has too many arguments specified.
ACmd.Parameters.Append ACmd.CreateParameter("ReturnValue", adInteger, adParamReturnValue)
ACmd.Parameters.Append ACmd.CreateParameter("InputX", adVarChar, adParamInput, 10, InputX)
ACmd.Parameters.Append ACmd.CreateParameter("InputY", adInteger, adParamInput, 6, InputY)
ACmd.Parameters.Append ACmd.CreateParameter("HasExpedite", adInteger, adParamOutput)
Dim RS As Recordset
Dim RecordsAffected As Long
'execute query that returns value
Call ACmd.Execute(RecordsAffected:=RecordsAffected, Options:=adExecuteNoRecords)
'execute query that returns recordset
'Set RS = ACmd.Execute(RecordsAffected:=RecordsAffected)
'get records affected, return value and output parameter
Debug.Print "Records affected: " & RecordsAffected
Debug.Print "Return value: " & ACmd.Parameters("ReturnValue")
Debug.Print "Output param: " & ACmd.Parameters("HasExpedite")
'use record set here
'...
'close
If Not RS Is Nothing Then RS.Close
ACon.Close
End Sub