Calling Oracle Stored procedure from VBA ADODB - vba

Hi
I am trying to use a stored procedure in WORD VBA to retrieve some addresses using a stored procedure to populate a list field.
Private Sub txtCpny_AfterUpdate()
Dim rst As ADODB.Recordset
Dim cmd As ADODB.Command
Dim param1 As ADODB.Parameter
Dim param2 As ADODB.Parameter
Dim strCpny As String
strCpny = GetSearchString(Me.txtCpny) 'ie %Name%
Set cmd = CreateObject("ADODB.Command")
With cmd
.ActiveConnection = mcn
.CommandText = "LISTPARTNER_NAME"
.CommandType = adCmdStoredProc
Set param1 = .CreateParameter("RCT1", adInteger, adParamInputOutput, , Null)
Set param2 = .CreateParameter("firmaName", adVarChar, adParamInput, 50, strCpny)
.Parameters.Append param1
.Parameters.Append param2
Set rst = .Execute
End With
...Using the recordset here
rst.Close
Set param1 = Nothing
Set param2 = Nothing
Set cmd = Nothing
End Sub
The Stored Procedure looks as follows: The SQL should result in a recordset holding the matching Companies.
PROCEDURE LISTPARTNER_NAME (
firmaName IN VARCHAR2 DEFAULT NULL,
RCT1 IN OUT GLOBALPKG.RCT1
)
AS
BEGIN
OPEN RCT1 FOR
SELECT
...
FROM
...
WHERE
KNAG.NAME_ORG LIKE LISTPARTNER_NAME.firmaName
...
END LISTPARTNER_NAME
When the command is executed VB throws a RunTime Error
ORA-06550: Line 1, column 13:
PLS-00306: wrong number or types of arguments in call to
'LISTPARTNER_NAME'
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
In my opinion the I am doing something wrong wit the parameters. Ihave been trying various versions of setting the parameters with no luck
Any Clues?
Thanks

have a look at this thread, it may be of assistance
http://forums.oracle.com/forums/thread.jspa?threadID=360922
The only other thing I could suggest would be switching the order of the parameters (so they are in the same order -- I know ODP defaults to order but I am unsure of ADODB)

I have been successfully using this code in Access:
Function runAdo(sql As String, usr As String, pwd As String)
'by Patrick Honorez - www.idevlop.com ----- 09-nov-2012
'Purpose : run Oracle proc using ADO connection
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Set cn = New ADODB.Connection
cn.Open GetPersonalizedConnectStringADO(usr, pwd)
Set rs = New ADODB.Recordset
rs.Open sql, cn, adOpenStatic, adLockReadOnly
cn.Close
End Function
I rarely use ADO from Access, since I find DAO simpler to use, but in this case I had to execute some Oracle procs requiring a different UID, and creating a new DAO Querydef specifying different UID and PWD, did not work, perhaps due to the fact that Access keeps a cache of connections.
So I decided to use ADO for the second "user" and it works like a charm.

Related

Cannot set Parameter size when using adLongVarChar in MS Access

I have a function that makes a call to a SQL Server database to return a String value. Previously, expected string values were fairly short, but as the character length can exceed 255 on occasion, I have changed the SQL field type in the table to nvarchar(MAX).
In the project, I have altered the code to use adLongVarChar instead of adVarChar and need to specify the length. As there is no length, I know for Input parameters, -1 is the correct length to use. However, when using this as an Output parameter, I receive Run-Time Error 3708 - 'Parameter object is improperly defined. Inconsistent or incomplete information was provided.'
What is the correct syntax to construct the paramter?
Code below:
Public Function getStatus() As String
Dim db As ADODB.Connection
Dim rs As ADODB.Recordset
Dim sp As ADODB.Command
Dim rp1 As ADODB.Parameter
Dim rp2 As ADODB.Parameter
'// Data declarations
Set db = New ADODB.Connection
Set rs = New ADODB.Recordset
Set sp = New ADODB.Command
Set rp1 = sp.CreateParameter("#ksActive", adBoolean, adParamOutput)
Set rp2 = sp.CreateParameter("#ksMsg", adLongVarChar, adParamOutput, -1)
'// Data connection initialisation
db.Open dbString
With sp
.ActiveConnection = db
.CommandText = "dbo.TestProcedureName"
.CommandType = adCmdStoredProc
.Parameters.Append rp1 '// This works fine
.Parameters.Append rp2 '// Error occurs here
.Execute
End With
getStatus = rp2.Value
End Function
TL/DR: Use .Parameters.Refresh and .NamedParameters = True to define output (return) parameters in MS Access ADODB.
I just came across this and had this same problem. I found a hint on MSDN "What is the ADO DataType for nVarchAR(max)". For whatever reason, you MUST include an initial value with the length (at least in Access VBA) for long value parameters in Access ADO. I found adding NULL works just fine to satisfy it, especially when you set the values later for stored commands.
NOTE: This will only work for input values (as shown here, outputs cannot be defined like this)
' Note: only works for output params.
Set rp2 = sp.CreateParameter("#ksMsg", adLongVarChar, adParamInput, -1, NULL)
Output Parameter definition:
Using OP's names:
Public Function getStatus() As String
Dim db As ADODB.Connection
Dim rs As ADODB.Recordset
Dim sp As ADODB.Command
Dim rp1 As ADODB.Parameter
Dim rp2 As ADODB.Parameter
'// Data declarations
Set db = New ADODB.Connection
Set rs = New ADODB.Recordset
Set sp = New ADODB.Command
'// Data connection initialisation
db.Open dbString
Dim sp As ADODB.Command
With sp
.ActiveConnection = db
.CommandText = "dbo.TestProcedureName"
.CommandType = adCmdStoredProc
.Parameters.Refresh
.NamedParameters = True
Set rp1 = .Parameters("#ksActive")
Set rp2 = .Parameters("#ksMsg")
' Set outputs to null because they're cached, and if your
' second call returns nothing, you'll get the prior call's results.
rp1.Value = Null
rp2.Value = Null
.Execute
End With
getStatus = rp2.Value
End Function
You need to use sp.Parameters.Refresh to define output parameters for stored procedures. After scouring the internet, it appears that there's an issue with using MS Access ADODB adLongVarWChar (or any long / wide return variable) and adParamOutput or adParamInputOutput and defining them explicitly.
I have found the only way to get Output Parameters to work is to use .Parameters.Refresh; once I did that, it works just fine (and returns correctly).
Just be sure to clear them out before executing (set outputs to null) or you'll get the previously cached result back (and it will send you on a wild goose chase).

ADODB.Command.Execute not working with parameter

I'm trying to create a function in VBA to handle my SQL procedure calls. I've run into a problem where if the code needs to supply a parameter to the procedure it is not working. The code is below, it works fine if I call the procedure without the optional argument. I've added a breakpoint before the execute; the if statement triggers fine and the immediate window tells me that ?cmd.Parameters(0) and ?cmd.Parameters(1) have values yet I get the error: myprocedure expects parameter '#sd_name' which was not supplied. The procedure only expects 2 arguments and I don't even care about the name, they can just be passed by position.
Function RunSQL(comtext As String, Optional Params As String = "No") As ADODB.Recordset
Dim cmd As New ADODB.Command
Dim recset As New ADODB.Recordset
Dim prm As ADODB.Parameter
TryConnect
cmd.commandtext = comtext
cmd.CommandType = adCmdText
cmd.ActiveConnection = GlobalCon
cmd.CommandTimeout = 0
If Params <> "No" Then
Set prm = cmd.CreateParameter("#sd_name", adVarChar, adParamInput, 100)
cmd.Parameters.Append prm
cmd.Parameters("#sd_name").Value = Params
Set prm = cmd.CreateParameter("#year_wk_num", adInteger, adParamInput, 100)
cmd.Parameters.Append prm
cmd.Parameters("#year_wk_num").Value = ThisWorkbook.Sheets("Control Sheet").Range("year_wk").Value
End If
--------------!Error Here----------------
Set recset = cmd.Execute
Set RunSQL = recset
Set cmd = Nothing
End Function
Got it, simple mistake, seems you cannot add parameters in this way to ADODB.Command.CommandType adCmdText rather it must be adCmdStoredProc. I guess you can probably add them as part of the commandtext string if you wish to use that type as msdn is saying it can be used as a textual definition of a stored procedure. However in this case I've just done the below and it's working fine (Still needs to be adCmdText when no parameters are required and calling VBA defined query string rather than procedure):
If Params <> "No" Then
cmd.CommandType = adCmdStoredProc 'added this line

Error trying to call stored procedure with prepared statement

I'm trying to use a prepared statement to call a stored procedure (using ADODB with classic ASP), but when I set CommandType I get the following error:
ADODB.Command error '800a0bb9'
Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another.
I have the following code:
With Server.CreateObject("ADODB.Command")
.ActiveConnection = db 'this is initialized prior
.CommandType = adCmdStoredProc
.CommandText = "procName"
End With
The prepared statement name is correct (I'm able to call it just by executing the string), and if I leave out the .CommandType and try calling .Execute, I get an error specifying:
Procedure or function 'procName' expects parameter '#ParamName', which was not supplied.
Even if I leave out the CommandType, I have no idea how to actually add the parameter (something along the following lines just results in the original error about arguments of the wrong type):
.Parameters.Append .CreateParameter("#ParamName",adVarChar,adParamInput,50,param)
I've also tried the following and got an error "Item cannot be found in the collection corresponding to the requested name or ordinal."
.Parameters.Refresh
.Parameters(0) = param
I've looked at several examples of how to call stored procedures using prepared statements, and it looks like I'm using the right syntax, but anything I try seems to result in some kind of error. Any help would be greatly appreciated.
You want something like this (untested)
Dim cmd, rs, ars, conn
Set cmd = Server.CreateObject("ADODB.Command")
With cmd
'Assuming passing connection string if passing ADODB.Connection object
'make sure you use Set .ActiveConnection = conn also conn.Open should
'have been already called.
.ActiveConnection = conn
'adCmdStoredProc is Constant value for 4 (include adovbs or
'set typelib in global.asa)
.CommandType = adCmdStoredProc
.CommandText = "dbo.procName"
'Define parameters in ordinal order to avoid errors
Call .Parameters.Append(.CreateParameter("#ParamName", adVarChar, adParamInput, 50))
'Set values using parameter friendly name
.Parameters("#ParamName").Value = param
'Are you returning a recordset?
Set rs = .Execute()
'Populate array with data from recordset
If Not rs.EOF Then ars = rs.GetRows()
Call rs.Close()
Set rs = Nothing
End With
Set cmd = Nothing
It is important to remember that the friendly name (as I rule I tend to match my parameter names in my stored procedure to my friendly names in ADO) you give your parameter means nothing to the stored procedure as ADO passes the parameters ordinally and nothing more, the fact you get the error;
Procedure or function 'procName' expects parameter '#ParamName', which was not supplied.
Suggests that the stored procedure is expecting your #ParamName parameter (defined in your stored procedure) value to be passed from ADO in a different ordinal position, which usually means you have not defined all your parameters or passed all the parameter values in the position they are expected.
You can also do a shortened version if your confident of your ordinal positioning and parameter requirements
With cmd
.ActiveConnection = conn
.CommandType = adCmdStoredProc
.CommandText = "dbo.procName"
'Pass parameters as array following ordinal position.
Set rs = .Execute(, Array(param))
'Populate array with data from recordset
If Not rs.EOF Then ars = rs.GetRows()
Call rs.Close()
Set rs = Nothing
End With
Set cmd = Nothing
Working with a 2-dimensional array is easy and negates the overhead of working directly with a ADODB.Recordset.
Dim row, rows
If IsArray(ars) Then
rows = UBound(ars, 2)
For row = 0 To rows
Response.Write "First column from row " & row & " = " & ars(0, row) & "<br />"
Next
Else
Response.Write "No data to return"
End If
Links
Using METADATA to Import DLL Constants - If your having trouble with the ADO constants (adCmdStoredProc etc.) this will fix it for you.
Here is how you call a stored procedure in ASP classic:
'Set the connection
'...............
'Set the command
DIM cmd
SET cmd = Server.CreateObject("ADODB.Command")
SET cmd.ActiveConnection = Connection
'Set the record set
DIM RS
SET RS = Server.CreateObject("ADODB.recordset")
'Prepare the stored procedure
cmd.CommandText = "procName"
cmd.CommandType = 4 'adCmdStoredProc
'Assign value to the parameter
cmd.Parameters("#ParamName ") = ParamValue
'Execute the stored procedure
RS = cmd.Execute
SET cmd = Nothing
'You can now access the record set
if (not RS.EOF) THEN
data = RS("column_name")
end if
'dispose your objects
RS.Close
SET RS = Nothing
Connection.Close
SET Connection = Nothing

VBA, ADO.Connection and query parameters

I have excel VBA script:
Set cоnn = CreateObject("ADODB.Connection")
conn.Open "report"
Set rs = conn.Execute("select * from table" )
Script work fine, but i want to add parameter to it. For example " where (parentid = myparam)", where myparam setted outside query string. How can i do it?
Of course i can modify query string, but i think it not very wise.
You need to use an ADODB.Command object that you can add parameters to. Here's basically what that looks like
Sub adotest()
Dim Cn As ADODB.Connection
Dim Cm As ADODB.Command
Dim Pm As ADODB.Parameter
Dim Rs as ADODB.Recordset
Set Cn = New ADODB.Connection
Cn.Open "mystring"
Set Cm = New ADODB.Command
With Cm
.ActiveConnection = Cn
.CommandText = "SELECT * FROM table WHERE parentid=?;"
.CommandType = adCmdText
Set Pm = .CreateParameter("parentid", adNumeric, adParamInput)
Pm.Value = 1
.Parameters.Append Pm
Set Rs = .Execute
End With
End Sub
The question mark in the CommandText is the placeholder for the parameter. I believe, but I'm not positive, that the order you Append parameters must match the order of the questions marks (when you have more than one). Don't be fooled that the parameter is named "parentid" because I don't think ADO cares about the name other than for identification.
Alternative example returning a command from a function:
Function BuildCommand(conn As ADODB.Connection) As ADODB.Command
Dim cmd As ADODB.Command
Set cmd = New ADODB.Command
cmd.ActiveConnection = conn
cmd.CommandType = adCmdText
cmd.Parameters.Append cmd.CreateParameter("#name", adVarChar, adParamInput, 255, "Dave")
cmd.CommandText = "SELECT * FROM users WHERE name = #name;"
Set BuildCommand = cmd
End Function
A couple things to note:
When using adVarChar data type, the size argument to cmd.CreateParameter (e.g. 255) is required. Not supplying it results a run-time error 3708: Application-defined or object-defined error, as indicated in the documentation:
If you specify a variable-length data type in the Type argument, you must either pass a Size argument or set the Size property of the Parameter object before appending it to the Parameters collection; otherwise, an error occurs.
If the cmd.ActiveConnection property is set when cmd.CommandText is set, and cmd.CommandText contains named parameters, cmd.Parameters will be populated accordingly. Calling cmd.Parameters.Append afterwards could result in duplicates. For example:
cmd.ActiveConnection = conn
cmd.CommandType = adCmdText
Debug.Print cmd.Parameters.Count ' 0
cmd.CommandText = "SELECT * FROM users WHERE name = #name;"
Debug.Print cmd.Parameters.Count ' 1
cmd.Parameters.Append cmd.CreateParameter("#name", adVarChar, adParamInput, 255, "Dave")
Debug.Print cmd.Parameters.Count ' 2
I believe this is what is meant in the documentation, which is slightly inaccurate:
If the Prepared property of the Command object is set to True and the Command object is bound to an open connection when you set the CommandText property, ADO prepares the query (that is, a compiled form of the query that is stored by the provider) when you call the Execute or Open methods.
As a workaround, either set cmd.CommandText or cmd.ActiveConnection after adding parameters.

Return value indicating update success/failure of SQL Server stored procedure via ADO/VBA

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