VBA calling function via VBA and ADO - oracle

I have a problem with calling my functions on Oracle server via VBA.
When I try calling function without parameters. It´s ok.
But, when I Calling functions with parameter. I get error ([Microsoft][ODBC driver for Oracle]Invalid parameter type)
Have any idea?
This is vba code and plsql (I make elementary function for test)
Vba
Private Sub test()
Dim Oracon As ADODB.Connection
Dim cmd As New ADODB.Command
Dim param1 As New ADODB.Parameter
Dim objErr As ADODB.Error
Set Oracon = CreateObject("ADODB.Connection")
mujuser = "xxxx"
mujPWD = "xxxxx"
strConn = "UID=" & mujuser & ";PWD=" & mujPWD & ";driver={Microsoft ODBC for Oracle};" & _
"SERVER=xx.xxx;"
Oracon.ConnectionString = strConn
Oracon.Open
cmd.ActiveConnection = Oracon
cmd.CommandText = "el_test"
cmd.CommandType = adCmdStoredProc
Set param1 = cmd.CreateParameter("P1", adLongVarChar, adParamInput, 256)
cmd.Parameters.Append param1
cmd.Parameters(0).Value = "ahoj1"
cmd.Execute
End Sub
And function
CREATE OR REPLACE FUNCTION EL_TEST
(
P1 IN VARCHAR2
) RETURN VARCHAR2 AS
BEGIN
RETURN 'Ahoj';
END EL_TEST;
Thanky you.

Get function return value with OLEDB
I searched high and low for this but finally solved the problem myself.
My solution is in VBScript but I have represented it in the (untested) code below.
The trick is that the first parameter is the return value.
Private Sub test()
Dim Oracon As ADODB.Connection
Dim cmd As New ADODB.Command
Dim param1 As New ADODB.Parameter
Dim param0 As New ADODB.Parameter
Dim objErr As ADODB.Error
Set Oracon = CreateObject("ADODB.Connection")
mujuser = "xxxx"
mujPWD = "xxxxx"
strConn = "UID=" & mujuser & ";PWD=" & mujPWD & ";driver={Microsoft ODBC for Oracle};" & _
"SERVER=xx.xxx;"
Oracon.ConnectionString = strConn
Oracon.Open
cmd.ActiveConnection = Oracon
cmd.CommandText = "el_test"
cmd.CommandType = adCmdStoredProc
Set param0 = cmd.CreateParameter("P0", adLongVarChar, adParamReturnValue, 256)
Set param1 = cmd.CreateParameter("P1", adLongVarChar, adParamInput, 256)
cmd.Parameters.Append param0
cmd.Parameters.Append param1
cmd.Execute
Dim result As String
result = param0.Value ' Use the variable you set. Same as cmd.Parameters(1).Value '
End Sub

I admit, I've never tried to execute a function like this through code, but I'm surprise this worked without the parameter because the way you have your function set up. I think the way you would want to get the value would be:
select el_test('ahoj1') from dual;
If you made this change from a function to a procedure, I think it will work the way you expect:
CREATE OR REPLACE procedure EL_TEST
( P1 IN VARCHAR2,
p2 out varchar2) is
BEGIN
p2 := 'Ahoj';
END EL_TEST;
And then your VBA would look like this:
Private Sub test()
Dim Oracon As ADODB.Connection
Dim cmd As New ADODB.Command
Dim param1 As New ADODB.Parameter
Dim objErr As ADODB.Error
Set Oracon = CreateObject("ADODB.Connection")
mujuser = "xxxx"
mujPWD = "xxxxxx"
strConn = "UID=" & mujuser & ";PWD=" & mujPWD & _
";driver={Microsoft ODBC for Oracle};SERVER=xxxx-xx"
Oracon.ConnectionString = strConn
Oracon.Open
cmd.ActiveConnection = Oracon
cmd.CommandText = "el_test"
cmd.CommandType = adCmdStoredProc
cmd.NamedParameters = True
cmd.Parameters.Append cmd.CreateParameter("P1", adVarChar, adParamInput, 256, "ahoj1")
cmd.Parameters.Append cmd.CreateParameter("P2", adVarChar, adParamOutput, 256)
cmd.Execute
Dim result As String
result = cmd.Parameters(1).Value
End Sub

Related

VBA Recordset / Oracle and Excel Connect

I've installed tries recordset in my vba statement.
Unfortunately he accesses only the first line in my database. Who can help me?
I'm not very good in VBA it's my first porject. I hope someone can help me with my code. Thank you
Sub Testbox()
Dim conn, Rs
Dim strSQL As String
Dim auswahl As Integer
auswahl = MsgBox("Die Daten werden geladen", vbOKCancel, "Bitte auswählen")
If auswahl = 1 Then
connstring = "UID=user;PWD=passwort;DRIVER={Microsoft ODBC For Oracle};SERVER=server.WORLD;"
Set conn = New ADODB.Connection
With conn
.ConnectionString = connstring
.CursorLocation = adUseClient
.Mode = adModeRead
.Open
End With
Set Rs = CreateObject("ADODB.Recordset")
strSQL = "select * from table where logdatum =1507"
Rs.Open strSQL, conn, 3, 3
Range("A2:A5000") = Rs("scanclient")
Range("B2:B500") = Rs("Sum")
Range("C2:C500") = Rs("batchclass")
Rs.Close
Set Rs = Nothing
conn.Close
Set conn = Nothing
Else
Exit Sub
End If
End Sub
Unfortunately, it is not possible to print data from Recordset into worksheet like that:
Range("A2:A5000") = Rs("scanclient")
Range("B2:B500") = Rs("Sum")
Range("C2:C500") = Rs("batchclass")
You need to replace this code with the below:
Dim i As Long: i = 1
Do Until Rs.EOF
i = i + 1
Cells(i, 1) = Rs("scanclient")
Cells(i, 2) = Rs("Sum")
Cells(i, 3) = Rs("batchclass")
Call Rs.MoveNext
Loop

ADO Oracle Operation is not allowed when the object is closed

I have an Excel 2013 VBA macro which needs to call an SQL procedure on an Oracle 12c database. The Oracle procedure is executed (it writes the result into a table) but in Excel I receive the error at Set rs = cmd.Execute:
Operation is not allowed when the object is closed
Below the code:
Dim v_userpw As String
Dim cnn As ADODB.Connection
Dim rs As New ADODB.Recordset
Dim cmd As New ADODB.Command
Dim l_userpw, l_reqid, l_pwhash, l_sighash As New ADODB.Parameter
Dim objErr As ADODB.Error
v_userpw = Cells(7, 1).Value
On Error GoTo err_test
'Set cnn = CreateObject("ADODB.Connection")
Set cnn = New ADODB.Connection
cnn.ConnectionString = "Provider=OraOLEDB.Oracle;Data Source=devdb;User ID=db1;Password=db1;"
cnn.Open
Set cmd = New ADODB.Command
Set cmd.ActiveConnection = cnn
Set l_userpw = cmd.CreateParameter("l_userpw", adVarChar, adParamInput, 1024, v_userpw)
cmd.Parameters.Append l_userpw
Set l_reqid = cmd.CreateParameter("l_reqid", adVarChar, adParamOutput, 1024)
cmd.Parameters.Append l_reqid
Set l_pwhash = cmd.CreateParameter("l_pwhash", adVarChar, adParamOutput, 1024)
cmd.Parameters.Append l_pwhash
Set l_sighash = cmd.CreateParameter("l_sighash", adVarChar, adParamOutput, 1024)
cmd.Parameters.Append l_sighash
'cmd.Properties("PLSQLRSet") = True
cmd.CommandText = "{CALL db1.genheader(?, ?, ?, ?)}"
Set rs = cmd.Execute
'cmd.Properties("PLSQLRSet") = False
Cells(8, 1) = rs.Fields("reqid").Value
Cells(9, 1) = rs.Fields("pwhash").Value
Cells(10, 1) = rs.Fields("sighash").Value
cnn.Close
err_test:
MsgBox Error$
For Each objErr In cnn.Errors
MsgBox objErr.Description
Next
cnn.Errors.Clear
Resume Next
The Oracle procedure looks like this:
create or replace procedure genheader (
l_userpw in varchar2,
l_reqid out varchar2,
--l_pwhash out raw,
--l_sighash out raw
l_vpwhash out varchar2,
l_vsighash out varchar2
)
I need to return the values in the predefined cells.
Does the procedure actually return a resultset? It looks like it just returns data using output parameters, so you wouldn't get the results from a recordset, you'd get them from the command parameters after the command executes.
cmd.Execute
Cells(8, 1) = cmd("l_reqid")
Cells(9, 1) = cmd("l_pwhash")
Cells(10, 1) = cmd("l_sighash")
Try testing the connection state to ensure it is open prior to assigning the connection to the ActiveConnection property of the command object. This can cause unstable behavior. If you don't want to do this in code, you can assign a breakpoint prior to the set line of code and check your locals window for the connection state. Also you need to specify the name of the Oracle Stored Procedure
cmd.Name = "genheader"
Cheers,
Boris

Write data to MS Access using VB6

This is my first VB6 application. My problem is there is no helpful example of writing data (including current date & time) from a form to an Access database. Here's my code based on all my research from different websites.
If you can't understand my code or if it is wrong, please show me a working example.
Private Sub Command1_Click()
Dim conConnection As New ADODB.Connection
Dim cmdCommand As New ADODB.Command
Dim rstRecordSet As New ADODB.Recordset
Dim logInId As Integer
Dim guardId As String
Dim studentId As String
Dim laptopName As String
Dim laptopBrand As String
Dim logInDate As Date
Dim logInTime As Date
guardId = Text2.Text
studentId = Text3.Text
laptopName = Text4.Text
laptopBrand = Text5.Text
logInDate = DateVal(Now)
logInTime = TimeVal(Now)
conConnection.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & _
App.Path & "\" & "Database.accdb;Mode=Read|Write"
conConnection.CursorLocation = adUseClient
conConnection.Open
rstRecordSet.Open "laptopLoggedInLoggedOutInfo", conConnection
logInId = rstRecordSet.RecordCount
With cmdCommand
.ActiveConnection = conConnection
.CommandType = adCmdText
'f means field
.CommandText = "INSERT INTO laptopLoggedInLoggedOutInfo(f1,f2,f3,f4,f5,f6,f7) VALUES (?,?,?,?,?,?,?) "
.Prepared = True
.Parameters.Append .CreateParameter("f1", adInteger, adParamInput, , logInId + 1)
.Parameters.Append .CreateParameter("f2", adChar, adParamInput, 20, guardId)
.Parameters.Append .CreateParameter("f3", adChar, adParamInput, 20, studentId)
.Parameters.Append .CreateParameter("f4", adChar, adParamInput, 20, laptopName)
.Parameters.Append .CreateParameter("f5", adChar, adParamInput, 20, laptopBrand)
.Parameters.Append .CreateParameter("f6", adDate, adParamInput, , logInDate)
.Parameters.Append .CreateParameter("f7", adDate, adParamInput, , logInTime)
Set rstRecordSet = cmdCommand.Execute
End With
conConnection.Close
Set conConnection = Nothing
Set cmdCommand = Nothing
Set rstRecordSet = Nothing
End Sub
I've made in-line comments on your code:
Private Sub Command1_Click()
Whilst this doesn't matter for this particular example, generally don't declare object variables "As New". It is better if you instantiate them manually. Essentially, "As New" declared variables are checked every time you try to use a property or method on them, and if the variable Is Nothing, it creates a new instance. This may not necessarily be what you intend.
Dim conConnection As New ADODB.Connection
Dim cmdCommand As New ADODB.Command
Dim rstRecordSet As New ADODB.Recordset
Dim logInId As Integer
Dim guardId As String
Dim studentId As String
Dim laptopName As String
Dim laptopBrand As String
Dim logInDate As Date
Dim logInTime As Date
guardId = Text2.Text
studentId = Text3.Text
laptopName = Text4.Text
laptopBrand = Text5.Text
logInDate = DateVal(Now)
logInTime = TimeVal(Now)
Make sure that the Data Source substring is points to your Access database.
conConnection.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & _
App.Path & "\" & "Database.accdb;Mode=Read|Write"
conConnection.CursorLocation = adUseClient
conConnection.Open
I see that you are using a recordset just to receive a count of records in logInId. I really wouldn't use this as an ID. If you delete records from the table, then your ID will become smaller. Generally, if you want a unique ID, you must ensure that the ID always increments.
rstRecordSet.Open "laptopLoggedInLoggedOutInfo", conConnection
logInId = rstRecordSet.RecordCount
My suggestion: use "SELECT MAX(f1) FROM laptopLoggedInLoggedOutInfo", and retrieve the first value, ensuring that if the value is null, it returns zero, e.g.
rstRecordSet.Open "SELECT MAX(logInId) FROM laptopLoggedInLoggedOutInfo", conConnection
logInId = IIf(IsNull(rstRecordSet.Fields(0)), 0, IsNull(rstRecordSet.Fields(0)))
With cmdCommand
.ActiveConnection = conConnection
.CommandType = adCmdText
'f means field
Are these really your fieldnames: f1, f2, f2, etc.? I would be surprised. Replace them with the correct field names.
.CommandText = "INSERT INTO laptopLoggedInLoggedOutInfo(f1,f2,f3,f4,f5,f6,f7) VALUES (?,?,?,?,?,?,?) "
Note that the actual parameter names, e.g. f1,f2,f3, etc. seem not to matter. It is the order in the INSERT statement that matters.
.Prepared = True
.Parameters.Append .CreateParameter("f1", adInteger, adParamInput, , logInId + 1)
.Parameters.Append .CreateParameter("f2", adChar, adParamInput, 20, guardId)
.Parameters.Append .CreateParameter("f3", adChar, adParamInput, 20, studentId)
.Parameters.Append .CreateParameter("f4", adChar, adParamInput, 20, laptopName)
.Parameters.Append .CreateParameter("f5", adChar, adParamInput, 20, laptopBrand)
.Parameters.Append .CreateParameter("f6", adDate, adParamInput, , logInDate)
.Parameters.Append .CreateParameter("f7", adDate, adParamInput, , logInTime)
Don't use a return value in use the following line. And INSERT statement returns no values:
Set rstRecordSet = cmdCommand.Execute
Do this instead:
cmdCommand.Execute
End With
conConnection.Close
You probably don't need to set these variables to Nothing - VB does it for you, anyway. However, if you do, it is generally good practice to do this in reverse order of creation.
Set conConnection = Nothing
Set cmdCommand = Nothing
Set rstRecordSet = Nothing
End Sub
There really isn't much advantage in using ACE formats, you only limit portability. MDBs are almost always a better idea.
You also have a ton of code there for something this minimal. And don't forget to escape the DB path, you can use apostrophes or quotes in the connection string.
Make your "f1" field type IDENTITY ("autonumber").
Private Sub Command1_Click()
Dim cn As ADODB.Connection
Dim cm As ADODB.Command
Set cn = New ADODB.Connection
cn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source='" _
& App.Path & "\Database.accdb';Mode=Read|Write"
Set cm = New ADODB.Command
With cm
.CommandType = adCmdText
'Assume "f1" is type IDENTITY ("Autonumber").
.CommandText = _
"INSERT INTO laptopLoggedInLoggedOutInfo(f2,f3,f4,f5,f6,f7) " _
& "VALUES (?,?,?,?,?,?)"
Set .ActiveConnection = cn
'Seriously? Give those TextBoxes names!
.Execute , _
Array(Text2.Text, Text3.Text, Text4.Text, Text5.Text, Date, Time()), _
adExecuteNoRecords
End With
End Sub

PL/SQL stored procedure out cursor to VBA ADODB.RecordSet?

To preface this post, I want to say that I am fairly new to Excel 2007 vba macros. I am trying to call an Oracle PL/SQL stored procedure that has a cursor as an output parameter. The procedure spec looks like this:
PROCEDURE get_product
(
out_cur_data OUT SYS_REFCURSOR,
rptid IN NUMBER,
scenario IN VARCHAR2
);
And I have written my macro as:
Sub GetProduct()
Const StartRow As Integer = 4
Dim conn As ADODB.Connection
Set conn = New ADODB.Connection
With conn
.ConnectionString = "<my connection string>"
.Open
End With
Dim cmd As ADODB.Command
Set cmd = New ADODB.Command
With cmd
.ActiveConnection = conn
.CommandType = adCmdText
.CommandText = "{call their_package.get_product({out_cur_data 100},?,?)}"
.NamedParameters = True
.Parameters.Append cmd.CreateParameter("rptid", adNumeric, adParamInput, 0, 98)
.Parameters.Append cmd.CreateParameter("scenario", adVarChar, adParamInput, 4, "decline001")
End With
Dim rs As ADODB.Recordset
Set rs = New ADODB.Recordset
With rs
.CursorType = adOpenStatic
.CursorLocation = adUseClient
.LockType = adLockOptimistic
End With
Set rs = cmd.Execute
Cells(StartRow + 1, 1).CopyFromRecordset rs
rs.Close
conn.Close
End Sub
This does not work obviously, I get a run-time error '-2147217900 (80040e14): One or more errors occurred during processing of command.' So, OK.
I am looking for some guidance/advice on how to bring back that cursor into an ADODB.RecordSet. I don't think I have set up the output cursor correctly for "out_cur_data", but my searches online for any help have come up dry so far. Can any give me a basic working example to help me understand what I am doing wrong?
BTW... I do not have control of the stored procedure at all, it is from an external package.
Any help is really appreciated.
Thanks,
Doran
I think it should be this one:
With cmd
.Properties("PLSQLRSet") = TRUE
.ActiveConnection = conn
.CommandType = adCmdText
.CommandText = "{call their_package.get_product(?,?)}"
.NamedParameters = True
.Parameters.Append cmd.CreateParameter("rptid", adNumeric, adParamInput, 0, 98)
.Parameters.Append cmd.CreateParameter("scenario", adVarChar, adParamInput, 4, "decline001")
End With
...
Set rs = cmd.Execute
cmd.Properties("PLSQLRSet") = FALSE
Note:
Although their_package.get_product() takes three parameters, only two need to be bound because Ref cursor parameters are automatically bound by the provider.
For more information check Oracle documentation: Oracle Provider for OLE DB Developer's Guide - "Using OraOLEDB with Visual Basic"

214721900 error during run time

What is wrong in this code:
Dim con As ADODB.Connection
Dim rec As ADODB.Recordset
Set con = New ADODB.Connection
Set rec = New ADODB.Recordset
Dim count As Integer
con.Open "Provider=MSDAORA.1;Password=****;User ID=system;Persist Security Info=False"
con.CursorLocation = adUseClient
rec.Open "select count(*) as c from login_hisab where username = " & Text1.Text & " and password = " & Text2.Text & "", con, adOpenDynamic, adLockOptimistic
count = rec.Fields("c")
If count = 0 Then
MsgBox "Invalid USERNAME or PASSWORD"
End If
You probably have to put your sql values inside single quotes:
where username = '" & Text1.Text & "' and password = '" & Text2.Text & "'"
Try using a parameterized query like this (air code). Means you don't have to worry about passwords containing ' or ", you don't have to worry about SQL Injection, etc.
dim cmd As ADODB.Command
Set cmd = New ADODB.Command
cmd.CommandType = adCmdText
cmd.CommandTimeout = 30
cmd.CommandText = "select count(*) as c from login_hisab where username = ? and password = ?"
cmd.Parameters.Append cmd.CreateParameter("userid", adVarChar, _
adParamInput, Len(Text1.Text), Text1.Text)
cmd.Parameters.Append cmd.CreateParameter("pwd", adVarChar, _
adParamInput, Len(Text2.Text), Text2.Text)
cmd.ActiveConnection = con
Set rec = cmd.Execute()
count = rec.Fields("c")
If count = 0 Then
MsgBox "Invalid USERNAME or PASSWORD"
End If

Resources