我需要使用 Delphi 中的以下参数调用一个名为 GetData
的 Oracle 函数:
(RESULT) NUMBER
P1 VARCHAR2 IN
P2 VARCHAR2 IN
P3 VARCHAR2 IN
P4 VARCHAR2 OUT
我尝试使用的代码是:
q := TADOQuery.Create(nil);
q.Connection := conn;
q.SQL.Add('BEGIN');
q.SQL.Add(' SELECT GetData(:IN_1,:IN_2,:IN_3,:OUT_1) into :OUT_2 from dual;');
q.SQL.Add('END;');
q.Parameters.ParamByName('IN_1').DataType:=ftString;
q.Parameters.ParamByName('IN_1').Direction:=pdInput;
q.Parameters.ParamByName('IN_1').Size:=3;
q.Parameters.ParamByName('IN_1').Value:='001';
q.Parameters.ParamByName('IN_2').DataType:=ftString;
q.Parameters.ParamByName('IN_2').Direction:=pdInput;
q.Parameters.ParamByName('IN_2').Size:=15;
q.Parameters.ParamByName('IN_2').Value:='88000000000';
q.Parameters.ParamByName('IN_3').DataType:=ftString;
q.Parameters.ParamByName('IN_3').Direction:=pdInput;
q.Parameters.ParamByName('IN_3').Size:=64;
q.Parameters.ParamByName('IN_3').Value:='';
q.Parameters.ParamByName('OUT_1').DataType:=ftString;
q.Parameters.ParamByName('OUT_1').Direction:=pdOutput;
q.Parameters.ParamByName('OUT_1').Size:=255;
q.Parameters.ParamByName('OUT_1').Value:='';
q.Parameters.ParamByName('OUT_2').DataType:=ftInteger;
q.Parameters.ParamByName('OUT_2').Direction:=pdOutput;
q.Parameters.ParamByName('OUT_2').Value:='0';
q.Open;
responseEdit.Text:=q.Parameters.ParamByName('OUT_1').Value;
但是我得到ORA-06572:函数 GETDATA 有 OUT 参数
。据我了解,不能在 Oracle 的 SELECT 语句中使用带有 OUT 参数的函数...
那么如何调用呢?
<小时 />例如,在 java 中,我设法使用以下语法来做到这一点:
CallableStatement cs = conn.prepareCall("{ call ? := GetData(?,?,?,?)}");
不幸的是,它在 Delphi 中不起作用......
<小时 />我还尝试使用语法调用它:
q.SQL.Add('BEGIN');
q.SQL.Add(' :OUT_2 := GetData(:IN_1,:IN_2,:IN_3,:OUT_1);');
q.SQL.Add('END;');
但是 Delphi 似乎误解了 :=
符号作为参数。因此,Oracle 已损坏,并且 PLS-00103:在期望以下其中一项 := 时遇到符号“”。 ( @ % ; Indicator
异常被抛出......或者如果我删除 :=
周围的空格,Delphi 已经抛出一些一般的 EOLEException。
我尝试使用 TADOStoredProc
进行调用:
stp := TADOStoredProc.Create(nil);
stp.Connection := conn;
//stp.ProcedureName:='GetData'; //also tried this
stp.ProcedureName:=':OUT_2 := GetData(:IN_1,:IN_2,:IN_3,:OUT_1)';
stp.Parameters.CreateParameter('OUT_2',ftInteger,pdOutput,4,0);
stp.Parameters.CreateParameter('IN_1',ftString,pdInput,3,'101');
stp.Parameters.CreateParameter('IN_2',ftString,pdInput,15,phoneEdit.Text);
stp.Parameters.CreateParameter('IN_3',ftString,pdInput,64,' ');
stp.Parameters.CreateParameter('OUT_1',ftString,pdOutput,255,' ');
stp.ExecProc;
它抛出一个未知的 OleException。当我指定过程名称(如 stp.ProcedureName:='GetData';
)时,它显示指定的参数数量或类型错误
。
我尝试使用 TADOCommand
执行相同操作:
cmd := TADOCommand.Create(nil);
cmd.Connection := conn;
cmd.CommandType := cmdStoredProc;
cmd.CommandText := ' :OUT_2 := GetData(:IN_1,:IN_2,:IN_3,:OUT_1); ';
...
Delphi 再次抛出未知的 OleException。
<小时 />因此,要么我对 oracle 和 delphi 使用了不正确的语法,要么我无法将参数传递给 delphi,以便它可以格式化对 oracle 的正确调用...
但是,当调用不带 OUT 参数的 oracle 函数时,或者当调用 ms sql 函数时(即使不带 out 参数...),所有这些都确实有效。那么这里有什么问题吗?
请您参考如下方法:
正如我在评论中所说,TADOStoredProc
已知可以在没有参数的情况下工作。
这是一个 SSCCE:
CREATE OR REPLACE FUNCTION ADMIN.GETDATA(IN_1 IN VARCHAR2,
IN_2 IN VARCHAR2,
IN_3 IN VARCHAR2,
OUT_1 IN OUT VARCHAR2) RETURN INTEGER
IS
BEGIN
OUT_1 := IN_1 || IN_2 || IN_3;
RETURN 5;
END;
在 PL/SQL 上这是有效的:
BEGIN
DECLARE OUTVAR VARCHAR(255);
RETVAR INTEGER;
BEGIN
RETVAR:= ADMIN.GETDATA('A','B','C', OUTVAR);
DBMS_OUTPUT.PUT_LINE(OUTVAR);
DBMS_OUTPUT.PUT_LINE(RETVAR);
END;
END;
输出页面是:
ABC
5
现在是德尔福代码:
var Proc: TADOStoredProc;
P: TParameter;
Results: String;
begin
Proc := TADOStoredProc.Create(nil);
try
(* Set up the connection to an Oracle database *)
Proc.Connection := MyADOConnection;
(* Define the function Name *)
Proc.ProcedureName := 'GETDATA';
(* Let the FrameWork retrieve all the parameters from DataBase *)
//Proc.Parameters.Refresh;
//Set parameters values
//Proc.Parameters.ParamByName('IN_1').Value := 'A';
//Proc.Parameters.ParamByName('IN_2').Value := 'B';
//Proc.Parameters.ParamByName('IN_3').Value := 'C';
//Proc.Parameters.ParamByName('OUT1').Value := ''; //This will be overrided by the database.
// **********************
// OR
// **********************
//Define it manually!
begin
//Defining the Return Value
Proc.Parameters.CreateParameter('RETVAL', ftBCD (* or ftInteger *), pdReturnValue, 0, Unassigned);
//Defining Input parameters 1, 2 and 3;
Proc.Parameters.CreateParameter('IN1', ftString , pdInput, 4000 (* This is the Max *), 'A');
//Collect the reference to update later
P := Proc.Parameters.CreateParameter('IN2', ftString , pdInput, 4000 (* Length for a *), Unassigned);
Proc.Parameters.CreateParameter('IN3', ftString , pdInput, 4000 (* ftString param *), 'C');
Proc.Parameters.CreateParameter('OUT1', ftString , pdOutput, 4000, Unassigned);
P.Value := 'B';
Proc.ExecProc;
// Expected : [Return Value : 5]~[Out Var: ABC]
Results := Format('[Return Value : %s]~[Out Var: %s]',
[VarToStr(Proc.Parameters.ParamByName('RETVAL').Value),
VarToStr(Proc.Parameters.ParamByName('OUT1').Value)]);
Proc.Close;
// ACTUAL : [Return Value : 5]~[Out Var: ABC]
ShowMessage(Results);
//IT WORKS!!
end;
finally
FreeAndNil(Proc);
end;