我需要使用 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; 


评论关闭
IT源码网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!