如何从Excal调用Oracle打包函数

我正在尝试在Oracle 11g数据库中执行一个包和函数。 我有下面的代码,但是,我得到第一个.Execute命令上的错误。

在VBA中的本地窗口给了我下面的错误:

Description : "Unspecified error" : String Number : -2147467259 : Long Source : "OraOLEDB" : String 

哦,我已经引用了Microsoft ActiveX Data Object 6.1 Library。

我已经尝试了各种更改的代码,但他们都返回相同的错误信息。

 Sub QueryGLComb() Dim OraCon As ADODB.Connection Dim recset As New ADODB.Recordset Dim cmd As New ADODB.Command Dim objErr As ADODB.Error Dim lngRow As Long On Error GoTo err_test Set OraCon = CreateObject("ADODB.Connection") OraCon.ConnectionString = "Provider=OraOLEDB.Oracle;" & _ "Data Source=DEMO;" & _ "User ID=scott;" & _ "Password=tiger;" OraCon.Open Set cmd = New ADODB.Command Set cmd.ActiveConnection = OraCon If OraCon.State = adStateClosed Then MsgBox "false" End If With cmd .ActiveConnection = OraCon .CommandText = "fnd_flex_keyval.validate_segs" .CommandType = adCmdStoredProc .CommandTimeout = 60 .Parameters.Append .CreateParameter("return", adBoolean, adParamReturnValue) .Parameters.Append .CreateParameter("operation", adVariant, adParamInput, , "CHECK_COMBINATION") .Parameters.Append .CreateParameter("appl_short_name", adVariant, adParamInput, , "SQLGL") .Parameters.Append .CreateParameter("key_flex_code", adVariant, adParamInput, , "GL#") .Parameters.Append .CreateParameter("structure_number", adNumeric, adParamInput, , "50268") .Parameters.Append .CreateParameter("concat_segments", adVariant, adParamInput, , "67000.2400.4001.01") .Parameters.Append .CreateParameter("validation_date", adVariant, adParamInput, , "sysdate") .Execute End With Set cmd = New ADODB.Command Set cmd.ActiveConnection = OraCon With cmd .ActiveConnection = OraCon .CommandText = "begin FND_FLEX_KEYVAL.ERROR_MESSAGE" .CommandType = adCmdStoredProc .Parameters.Append .CreateParameter("message", adVariant, adParamReturnValue) .Execute End With MsgBox "Return Message = " & cmd.Parameters(0) OraCon.Close err_test: MsgBox Error$ For Each objErr In OraCon.Errors MsgBox objErr.Description Next OraCon.Errors.Clear Resume Next End Sub 

第一个“.Execute”行是错误发生的地方。

这里是我在SQLDeveloper / Toad中使用的Oracle代码。 我正在调用的包是“FND_FLEX_VALIDATE”,函数是“VALIDATE_SEGS”。 这是Oracle提供的Oracle eBS中的软件包。 如果对fnd_flex_keyval.validate_segs的初始调用返回true,那么一切都很好。 如果它返回一个错误,那么我们必须调用“FND_FLEX_KEYVAL.ERROR_MESSAGE”来检索错误信息。

 DECLARE l_return boolean; l_message varchar2(240); BEGIN l_return := fnd_flex_keyval.validate_segs(operation => 'CHECK_COMBINATION' ,appl_short_name => 'SQLGL' ,key_flex_code => 'GL#' ,structure_number => 50268 --- Pass your chart of accounts id ,concat_segments => '67000.2400.4001.01' --- Pass your account combination string you want to create ,validation_date => sysdate); --- effective date by which you want the combination to be validated l_message := FND_FLEX_KEYVAL.ERROR_MESSAGE; If l_return THEN dbms_output.put_line('Valid'); Else dbms_output.put_line(l_message); End if; END; 

我已经创build了一个新的文件来testing。 我试图执行的程序现在有3个参数:1进2出。 同样,当代码到达.Execute命令时,我仍然收到相同的错误。

 Sub ExecutePackageP() Dim OraCon As New ADODB.Connection Dim recset As New ADODB.Recordset Dim cmd As New ADODB.Command Dim objErr As ADODB.Error Dim lngRow As Long On Error GoTo err_test Set OraCon = CreateObject("ADODB.Connection") OraCon.ConnectionString = "Provider=OraOLEDB.Oracle;" & _ "Data Source=demo;" & _ "User ID=scott;" & _ "Password=tiger;" OraCon.Open cmd.ActiveConnection = OraCon If OraCon.State = adStateClosed Then MsgBox "false" End If With cmd .ActiveConnection = OraCon .CommandType = adCmdStoredProc .CommandText = "XXX_VALIDATE_ACCOUNT" .CommandTimeout = 60 .Parameters.Append .CreateParameter("param1", adVariant, adParamInput, , "67000.2400.4001.01") .Parameters.Append .CreateParameter("param2", adBoolean, adParamOutput) .Parameters.Append .CreateParameter("param3", adVariant, adParamOutput) .Execute End With MsgBox "Reurtn = P_CCID=" & cmd.Parameters(1) & "; P_RESULT=" & cmd.Parameters(2) & ";" OraCon.Close End sub 

我将参数types从adVariant更改为adVarchar,并收到一条错误消息,指出Parameter对象定义不正确。 只有adVariant似乎工作。 我想起了一个网站,显示了在不同的数据库执行时使用的types,它说varchar2使用adVariant。 为xxx_validate_account添加过程代码:(注意,此过程调用一个名为fnd_flex_ext.get_ccid的内部oracle函数)

 CREATE OR REPLACE PROCEDURE APPS."XXX_VALIDATE_ACCOUNT" (p_account_flex in varchar2, p_valid out boolean, p_message out varchar2) is x_structure_id number; x_ccid number := 0; pragma autonomous_transaction; begin execute immediate 'alter session set nls_language = ''AMERICAN'''; p_valid := false; select chart_of_accounts_id into x_structure_id from gl_ledgers where short_name = 'XXX'; x_ccid := fnd_flex_ext.get_ccid(application_short_name => 'SQLGL', key_flex_code => 'GL#', structure_number => x_structure_id, validation_date => to_char(sysdate,'YYYY/MM/DD HH24:MI:SS'), concatenated_segments => p_account_flex); if x_ccid > 0 then p_valid := true; commit; else p_valid := false; p_message := fnd_message.get; end if; exception when others then p_message := sqlerrm; p_valid := false; end xxx_validate_account; / 

更新:25/09/2015:不幸的是我不能更新包,由于其他包和应用程序使用它。 所以,我决定用一个简单的函数来创build一个新的包来玩。 我确保input和输出不是布尔值,以免出现问题。 尽pipe如此,我还是遇到了同样的问题! 我试图在参数string中使用“adVarchar,100”,但excel只是告诉我,参数是错误的types。 认真思考我的机器有一些问题…

新的function和代码如下:

 create or replace package apps.xxxx_return_username is function return_username (p_user_id in number) return varchar2; end xxxx_return_username; / create or replace package body apps.xxxx_return_username as function return_username(p_user_id in number) return varchar2 is x_user_name varchar2(100); begin select user_name into x_user_name from apps.fnd_user where user_id = p_user_id; return x_user_name; exception when no_data_found then return 'xxxxx'; end return_username; end xxxx_return_username; / Sub newfunctioncall() Dim OraCon As New ADODB.Connection Dim recset As New ADODB.Recordset Dim cmd As New ADODB.Command Set OraCon = CreateObject("ADODB.Connection") OraCon.ConnectionString = "Provider=OraOLEDB.Oracle;" & _ "Data Source=demo;" & _ "User ID=scott;" & _ "Password=tiger;" OraCon.Open Set cmd = New ADODB.Command Set cmd.ActiveConnection = OraCon If OraCon.State = adStateClosed Then MsgBox "false" End If Set param1 = cmd.CreateParameter("param1", adNumeric, adParamInput, , "15483") cmd.Parameters.Append param1 Set param2 = cmd.CreateParameter("param2", adVariant, , adParamReturnValue) cmd.Parameters.Append param2 cmd.CommandType = adCmdStoredProc cmd.CommandText = "xxecu_return_username.return_username" Set recset = cmd.Execute MsgBox "Reurtn = USERNAME=" & cmd.Parameters(0) OraCon.Close End Sub 

你怎么知道你在Oracle数据库中执行一个有效的命令? 你可能想先试用SQLplus。 不太清楚你的function在哪里。 有可能:

 begin FND_FLEX_KEYVAL.ERROR_MESSAGE 

但这不是一个完整的说法。 至less它需要以下内容。

 begin FND_FLEX_KEYVAL.ERROR_MESSAGE; end; 

但是,如果FND_FLEX_KEYVAL.ERROR_MESSAGE是一个函数,则前面的代码也不会运行。 在这种情况下,您要select函数值:

 select FND_FLEX_KEYVAL.ERROR_MESSAGE from dual 

描述你问题的背景很好

我看到一些可能出现问题的地方。 如果不知道究竟是哪一个,我认为这是一个能够做你所寻求的代码的例子,尽pipe我承认我可能有一些错误的东西。

首先,在你的程序中,如果你声明你的variables为参数:

 create or replace procedure validate_segs( operation in varchar2, appl_short_name in varchar2, key_flex_code in varchar2, structure_number in number, concat_segments in varchar2, validation_date in date, message out varchar2, results out numeric ) as BEGIN message := 'Hello'; results := 1; END; 

那么,在VBA中,我认为你可以做这样的事情。 有了VBA / OleDB和Oracle,我从来没有得到布尔performance。 他们在C#中工作得很好,但是我还没有成功使用VBA,所以我把它转换成了一个这个例子的数字,这个例子似乎总是在VBA中转换为一个布尔值。

 With cmd .ActiveConnection = OraCon .CommandText = "validate_segs" .CommandType = adCmdStoredProc .CommandTimeout = 60 .NamedParameters = True .Parameters.Append .CreateParameter( _ "operation", adVarChar, adParamInput, 255, "CHECK_COMBINATION") .Parameters.Append .CreateParameter( _ "appl_short_name", adVarChar, adParamInput, 255, "SQLGL") .Parameters.Append .CreateParameter( _ "key_flex_code", adVarChar, adParamInput, 255, "GL#") .Parameters.Append .CreateParameter( _ "structure_number", adNumeric, adParamInput, 10, 50268) .Parameters.Append .CreateParameter( _ "concat_segments", adVarChar, adParamInput, 255, "67000.2400.4001.01") .Parameters.Append .CreateParameter( _ "validation_date", adDate, adParamInput, , Now()) .Parameters.Append .CreateParameter("message", adVarChar, adParamOutput, 255) .Parameters.Append .CreateParameter("return", adNumeric, adParamOutput, 1) .Execute End With 

然后,实际上从存储过程中挖掘结果:

 Dim result As Boolean Dim message As String message = cmd.Parameters(6).Value result = cmd.Parameters(7).Value 

我意识到你可能会被locking到VBA中,但如果你有select的机会,.NET的界面提供了一个更好的环境来debugging这种事情。

– 编辑9/24/15 –

我认为你的代码已经差不多了,但是我还能看到两个剩余的问题,其中一个我不是100%肯定是问题,但是我认为另一个问题是。 在我的解决scheme中,我很早就回避了这个问题,但现在我认为这可能是核心问题:看起来OLEDB和Oracle布尔人不能很好地结合在一起。 看到这篇文章:

https://support.microsoft.com/en-us/kb/306530

为了解决这个问题,如果你在Oracle和VBA中切换到一个数字,它应该可以工作。

另一个问题,我不确定是否真实,你是否正在使用Variant Dbtypes,当我认为你应该使用string(或Varchar)Dbtypes。 你提到你在文档中看到使用变体,所以也许这并不重要…但Varchar将工作。 你确实需要文本长度的附加参数才能正确编译(我使用了255个脚本)。

所以,我build议的两个变化是:

1)在您的存储过程中从布尔变为数字:

 CREATE OR REPLACE PROCEDURE "XXX_VALIDATE_ACCOUNT" ( p_account_flex in varchar2, p_valid out number, p_message out varchar2) is -- blah blah blah p_valid := 0; 

2)更改您的VBA代码以期望返回一个数字(并将Variant转换为Varchar)

 .Parameters.Append .CreateParameter("param1", adVarChar, adParamInput, 255, _ "67000.2400.4001.01") .Parameters.Append .CreateParameter("param2", adNumeric, adParamOutput) .Parameters.Append .CreateParameter("param3", adVarChar, adParamOutput, 255) 

即使你把它作为一个布尔值

 Dim result As Boolean result = cmd.Parameters(1).Value 

我必须说,debugging器返回的错误消息根本没有帮助。