Oracle 递归PL/SQL流水线函数调用导致ORA-00603

Oracle 递归PL/SQL流水线函数调用导致ORA-00603,oracle,recursion,plsql,pipelined-function,Oracle,Recursion,Plsql,Pipelined Function,我是PL/SQL方面的新手,我想编写一个流水线函数来提取付款主表的详细信息。这是密码 CREATE OR REPLACE FUNCTION F_GetImputationsReglement(Pregid Number) RETURN ImputationsReglementTable PIPELINED IS BEGIN DECLARE ImputationRow Regimputation%ROWTYPE; type cc is REF CURSOR RETURN Imputati

我是PL/SQL方面的新手,我想编写一个流水线函数来提取付款主表的详细信息。这是密码

CREATE OR REPLACE FUNCTION F_GetImputationsReglement(Pregid Number)  RETURN 
ImputationsReglementTable PIPELINED IS

BEGIN
DECLARE
ImputationRow  Regimputation%ROWTYPE;
 type cc is REF CURSOR RETURN ImputationRow%ROWTYPE;
 cur0 cc;
 CurrentRow   ImputationRow%ROWTYPE  ;
 out_rec      ImputationReglementRow := ImputationReglementRow (null, 
null,null, null,null);
 vquery VARCHAR2(1000);
 l_result ImputationReglementRow;
BEGIN
OPEN cur0 FOR
select * from regimputation WHERE regid = pregid;
  loop
  Fetch cur0 into CurrentRow;
  EXIT WHEN cur0%NOTFOUND;
  IF CurrentRow.RIMSENS = 'C' OR CurrentRow.RIMSENS IS NULL THEN
     IF CurrentRow.facid IS NOT NULL OR (CurrentRow.facid IS NULL AND 
    CurrentRow.RIMLETTRAGE IS NULL AND CurrentRow.RUBID IS NOT NULL) THEN
        out_rec.REGID         := CurrentRow.REGID;
        out_rec.FACID         := CurrentRow.FACID;
        out_rec.RIMMT         := CurrentRow.RIMMT;
        out_rec.FECORDRE      := CurrentRow.FECORDRE;
        out_rec.RUBID         := CurrentRow.RUBID;
        PIPE ROW(out_rec);
     ELSE
        IF CurrentRow.facid IS NULL AND CurrentRow.RIMLETTRAGE is NOT null 
and CurrentRow.RUBID IS NOT NULL THEN
          vQuery := 'select * from 
table(F_GetImputationsReglement(f_getREGID('''|| CurrentRow.RIMLETTRAGE 
||''')))';
          EXECUTE IMMEDIATE vquery into l_result;
           PIPE ROW(l_result);
         END IF; 
    END IF;
  END IF;  
  END LOOP;
  CLOSE cur0;
 RETURN;
   END;
END;
递归性的退出条件为:

  IF CurrentRow.RIMSENS = 'C' OR CurrentRow.RIMSENS IS NULL THEN
但是当我执行查询时

select * from table(f_getimputationsReglement(696213))
我得到一个错误:

ORA-00603 ORACLE Server会话因致命错误而终止

有人对这个有想法吗​​是什么


谢谢。

这不是对您问题的回答,但我建议您在动态查询中使用绑定变量。 可以重写以下内容以使用绑定变量:

vquery := 'select * from table(F_GetImputationsReglement(f_getREGID(''' || currentrow.rimlettrage ||
                                ''')))';
 execute immediate vquery
              into l_result;


如果有机会,我会用一种简单的方式重写你的代码。我做了一些假设并编写了一个简短的代码。可以替换为实际的表列。另外,当您调用递归时,代码可能会进入无限循环,并且永远不会退出并抛出您得到的错误。例如,我共享一个简单的代码。如果您喜欢下面的内容,请参见下面的内容,代码将采用infinte递归

在本例中,var是一个对象的表

CREATE OR REPLACE FUNCTION getSoccerLists
  RETURN var
IS
  --Initialization
  LIST VAR :=var();
  list1 VAR :=var();
BEGIN
  SELECT v_var( NSO ,NAME) BULK COLLECT INTO LIST FROM TEST;
  list1:= getSoccerLists;
  RETURN list;
END;
您可以重新编写代码:

考虑到你有一个目标:

CREATE TYPE v_var IS OBJECT
(
col1 NUMBER,
col1 NUMBER,
col1 number
);

Create type ImputationsReglementTable is table of v_var;


CREATE OR REPLACE  FUNCTION F_GetImputationsReglement(  Pregid NUMBER)
    RETURN ImputationsReglementTable PIPELINED
  IS
  BEGIN   
     var  ImputationsReglementTable:=ImputationsReglementTable();
     l_result ImputationsReglementTable:=ImputationsReglementTable();
    BEGIN    
      --Assuming table regimputation has col1 , col2 and col2
      SELECT * 
      BULK COLLECT INTO var
      FROM regimputation 
      WHERE regid = pregid;

      FOR i IN 1..var.count
      loop      
        IF var(i).COL1  = 'C' OR var(i).col1 IS NULL THEN

         IF var(i).col2 IS NOT NULL OR (var(i).col2 IS NULL AND var(i).col1 IS NULL AND var(i).col2 IS NOT NULL) THEN

          PIPE ROW(v_var(var(i)));          

          ELSE
          IF var(i).col1 IS NULL AND var(i).col1 IS NOT NULL AND var(i).col2 IS NOT NULL THEN
            vQuery            := 'select * from table(F_GetImputationsReglement(f_getREGID('''|| var(i).col1 ||''')))';
            EXECUTE IMMEDIATE vquery BULK COLLECT INTO l_result;
            FOR j IN 1..l_result.count
            loop
             PIPE ROW(v_var(l_result(j)));
            end loop;
          END IF;
        END IF;
      END IF;
    END LOOP;   
    RETURN;
  END;
END;

谢谢您的回答,但正如我所说的,我是PL/SQL新手,没有使用BULK,所以我有很多语法错误。 我对代码进行了如下修改,效果良好:

CREATE OR REPLACE FUNCTION F_GetImputationsReglement(Pregid Number)  RETURN 
ImputationsReglementTable PIPELINED IS

BEGIN
DECLARE
 Type tmpOut  is record
(
       REGID Number(20),
       FACID Number(20),
       RIMMT NUMBER(12,3),
       FECORDRE Number(3),
       RUBID            Number(3)
);

 ImputationRow  Regimputation%ROWTYPE;
 type cc is REF CURSOR RETURN ImputationRow%ROWTYPE;
 type cc2 is REF CURSOR  return tmpOut;
 cur0 cc;
 cur00 cc2; 
 CurrentRow                          ImputationRow%ROWTYPE  ;
 out_rec                             ImputationReglementRow := 
ImputationReglementRow (null, null,null, null,null);
 CurrentRow2                        tmpOut;                   
BEGIN
OPEN cur0 FOR
select * from regimputation WHERE regid = pregid;
  loop
  Fetch cur0 into CurrentRow;
  EXIT WHEN cur0%NOTFOUND;
  IF CurrentRow.RIMSENS = 'C' OR CurrentRow.RIMSENS IS NULL THEN --Condition de sortie
     IF CurrentRow.facid IS NOT NULL OR (CurrentRow.facid IS NULL AND CurrentRow.RIMLETTRAGE IS NULL AND CurrentRow.RUBID IS NOT NULL) THEN
        out_rec.REGID         := CurrentRow.REGID;
        out_rec.FACID         := CurrentRow.FACID;
        out_rec.RIMMT         := CurrentRow.RIMMT;
        out_rec.FECORDRE      := CurrentRow.FECORDRE;
        out_rec.RUBID         := CurrentRow.RUBID;
        dbms_output.put_line('Facture ' || CurrentRow.FACID);
        PIPE ROW(out_rec);
     ELSE
        IF CurrentRow.facid IS NULL AND CurrentRow.RIMLETTRAGE is NOT null and CurrentRow.RUBID IS NOT NULL THEN
           open cur00 for 
           select * from table(F_GetImputationsReglement(f_getREGID(CurrentRow.RIMLETTRAGE)));
           loop
           Fetch cur00 into CurrentRow2;
           EXIT WHEN cur00%NOTFOUND;
           out_rec.REGID         := CurrentRow2.REGID;
           out_rec.FACID         := CurrentRow2.FACID;
           out_rec.RIMMT         := CurrentRow2.RIMMT;
           out_rec.FECORDRE      := CurrentRow2.FECORDRE;
           out_rec.RUBID         := CurrentRow2.RUBID;
           dbms_output.put_line('Facture ' || CurrentRow2.FACID);
           PIPE ROW(out_rec);
        END LOOP;
        CLOSE cur00;
    END IF;
    END IF;
  END IF;
  END LOOP;
  CLOSE cur0;
 RETURN;
END;
END;

服务器上的内部错误。有关错误的详细信息,请查看database alert.log。服务器很好,我对递归调用有疑问,我认为它会不确定地溢出调用堆栈。查看alert.log没有什么坏处。你可能会在那里学到一些东西,还没开始工作。我忘了提到,根据您的建议,它适用于一个简单的情况rimmletrage为null,但当它不为null时,我需要进入其他级别以提取所有细节Dear Habib…在s.O.中有一种特殊的方式表示感谢。请阅读:
CREATE OR REPLACE FUNCTION F_GetImputationsReglement(Pregid Number)  RETURN 
ImputationsReglementTable PIPELINED IS

BEGIN
DECLARE
 Type tmpOut  is record
(
       REGID Number(20),
       FACID Number(20),
       RIMMT NUMBER(12,3),
       FECORDRE Number(3),
       RUBID            Number(3)
);

 ImputationRow  Regimputation%ROWTYPE;
 type cc is REF CURSOR RETURN ImputationRow%ROWTYPE;
 type cc2 is REF CURSOR  return tmpOut;
 cur0 cc;
 cur00 cc2; 
 CurrentRow                          ImputationRow%ROWTYPE  ;
 out_rec                             ImputationReglementRow := 
ImputationReglementRow (null, null,null, null,null);
 CurrentRow2                        tmpOut;                   
BEGIN
OPEN cur0 FOR
select * from regimputation WHERE regid = pregid;
  loop
  Fetch cur0 into CurrentRow;
  EXIT WHEN cur0%NOTFOUND;
  IF CurrentRow.RIMSENS = 'C' OR CurrentRow.RIMSENS IS NULL THEN --Condition de sortie
     IF CurrentRow.facid IS NOT NULL OR (CurrentRow.facid IS NULL AND CurrentRow.RIMLETTRAGE IS NULL AND CurrentRow.RUBID IS NOT NULL) THEN
        out_rec.REGID         := CurrentRow.REGID;
        out_rec.FACID         := CurrentRow.FACID;
        out_rec.RIMMT         := CurrentRow.RIMMT;
        out_rec.FECORDRE      := CurrentRow.FECORDRE;
        out_rec.RUBID         := CurrentRow.RUBID;
        dbms_output.put_line('Facture ' || CurrentRow.FACID);
        PIPE ROW(out_rec);
     ELSE
        IF CurrentRow.facid IS NULL AND CurrentRow.RIMLETTRAGE is NOT null and CurrentRow.RUBID IS NOT NULL THEN
           open cur00 for 
           select * from table(F_GetImputationsReglement(f_getREGID(CurrentRow.RIMLETTRAGE)));
           loop
           Fetch cur00 into CurrentRow2;
           EXIT WHEN cur00%NOTFOUND;
           out_rec.REGID         := CurrentRow2.REGID;
           out_rec.FACID         := CurrentRow2.FACID;
           out_rec.RIMMT         := CurrentRow2.RIMMT;
           out_rec.FECORDRE      := CurrentRow2.FECORDRE;
           out_rec.RUBID         := CurrentRow2.RUBID;
           dbms_output.put_line('Facture ' || CurrentRow2.FACID);
           PIPE ROW(out_rec);
        END LOOP;
        CLOSE cur00;
    END IF;
    END IF;
  END IF;
  END LOOP;
  CLOSE cur0;
 RETURN;
END;
END;