我试图从 sys_refcursor 获取 bulkcollect 记录并尝试使用 forall 插入另一个表,但它抛出了一条错误消息

Posted

技术标签:

【中文标题】我试图从 sys_refcursor 获取 bulkcollect 记录并尝试使用 forall 插入另一个表,但它抛出了一条错误消息【英文标题】:I tried to fetch bulkcollect records from sys_refcursor and tried to insert another table using forall but it throw an error message 【发布时间】:2020-02-08 13:25:28 【问题描述】:

--我的第一个程序

CREATE OR REPLACE PROCEDURE P1(V_SALARY NUMBER,OUTPUT_VALUE OUT SYS_REFCURSOR)
AS
BEGIN
  OPEN OUTPUT_VALUE FOR 
  SELECT FIRST_NAME,LAST_NAME
    FROM EMPLOYEES
   WHERE SALARY >V_SALARY;
END;

--第二道工序

CREATE OR REPLACE PROCEDURE P2(V_SAL NUMBER)
AS
RETURN_VALUE SYS_REFCURSOR;
  TYPE TTT IS RECORD(FIRST_NAME VARCHAR2(30),LAST_NAME VARCHAR2(20)) ;
  I TTT;
  TYPE TNAME IS TABLE OF TTT INDEX BY BINARY_INTEGER;
  K TNAME;
BEGIN
  P1(V_SAL,RETURN_VALUE);
  FETCH RETURN_VALUE BULK COLLECT INTO K;
  FORALL X IN K.FIRST..K.LAST 
    INSERT INTO T1 VALUES (K(X).FIRST_NAME,K(X).LAST_NAME);
  CLOSE RETURN_VALUE;
END;
/

第 12 行出现错误:PLS-00436:实施限制:无法引用 BULK In-BIND 记录表的字段

但是如果我尝试插入 for 循环,那么它工作正常..当我使用 Forall(批量绑定)时它不工作

【问题讨论】:

如果以下工作,请告诉我:INSERT INTO T1 VALUES K(X); 不..它不起作用@Tejash 帮我解决@Moudiz 是否抛出同样的错误?? 您的 Oracle 版本是多少? PLS-00436 听起来像 Oracle 10g。 【参考方案1】:

当您在从另一个过程返回collectionsys_refcursor 时尝试进行批量绑定时,这看起来像是一些错误或限制。 但是,您还有许多其他选项,而不是批量绑定(使用 FORALL 循环),它们的性能相同。

替代方案如下:

餐桌准备:

Create table employees (
  first_name   varchar2(100),
  last_name    varchar2(100),
  salary       number
);

Insert into employees values('A','B',1000);
Insert into employees values('C','D',2000);
Insert into employees values('E','F',3000);


Create table t1 (
  first_name   varchar2(100),
  last_name    varchar2(100)  
);

--Using Objects in place of records and sys_refcursor.
Create or replace type return_value is Object (
  first_name   varchar2(100),
  last_name    varchar2(100)  
);

Create or replace  type v_ret_val is table of return_value;

选项 1:将 P1 声明为 Function,然后使用集合作为直接路径插入。

CREATE OR REPLACE function p1 (v_salary NUMBER)      
 return v_ret_val
  AS
  abc v_ret_val;
BEGIN
  SELECT return_value(first_name,last_name) 
  Bulk collect into
    abc
  FROM employees
  WHERE salary > v_salary;

 Return abc;
END;
---------------    
CREATE OR REPLACE PROCEDURE p2 (
      v_sal NUMBER
    ) AS
      k   v_ret_val;
    BEGIN     

      k:=p1(v_sal);

      --Displaying values of collection
      For i in 1..k.count
      Loop
        dbms_output.put_line(k(i).first_name || k(i).last_name);
      End Loop;

      --Direct path insert
      INSERT /*+Append*/ INTO t1
      Select t.first_name,t.last_name
      from (table( k )) t;
      COMMIT;
    END;

选项 2:使用 OUT 参数将 P1 声明为 procedure,然后使用集合作为直接路径插入。

CREATE OR REPLACE procedure p11 (
  v_salary NUMBER
  ,output_value OUT v_ret_val
) 
AS  
BEGIN
  SELECT return_value(first_name,last_name) 
  Bulk collect into
    output_value
  FROM employees
  WHERE salary > v_salary;

END;
------------------------------

CREATE OR REPLACE PROCEDURE p2 ( v_sal NUMBER) 
AS
  k   v_ret_val;
BEGIN
  p11(v_sal,k);     

  For i in 1..k.count
  Loop
    dbms_output.put_line(k(i).first_name || k(i).last_name);
  End Loop;

  INSERT /*+Append*/ INTO t1
  Select t.first_name,t.last_name
  from (table( k )) t;

END;

选项 3:将 P1 声明为 procedure 并使用 OUT 参数,然后将 Merging 与目标 Table 的集合。

CREATE OR REPLACE PROCEDURE p2 (
  v_sal NUMBER
) AS
  k   v_ret_val;
BEGIN
  p11(v_sal,k);     

  For i in 1..k.count
  Loop
    dbms_output.put_line(k(i).first_name || k(i).last_name);
  End Loop;  

MERGE INTO t1 tgt 
  Using ( Select t.first_name,
                                   t.last_name
                            from table ( k ) t
                          ) src
  on (
    tgt.first_name = src.first_name 
    and tgt.last_name = src.first_name
    )
  When not matched 
  then 
   insert (
           tgt.first_name,
           tgt.last_name
         ) 
   values (
            src.first_name,
            src.last_name
          );     
END;

执行:

 Exec P2(1000);

输出:

SQL> Select * from t1;

    FIRST_NAME                         LAST_NAME
    -------------------------------------------
    E                                     F
    C                                     D

【讨论】:

以上是关于我试图从 sys_refcursor 获取 bulkcollect 记录并尝试使用 forall 插入另一个表,但它抛出了一条错误消息的主要内容,如果未能解决你的问题,请参考以下文章

Oracle - pl sql 从 SYS_REFCURSOR 中选择

从 Java 创建并将 SYS_REFCURSOR 作为输入参数传递给 Oracle 过程

如何将行附加到现有的 SYS_REFCURSOR?

如何从 Java 中的 oracle SP 返回 sys_refcursor?

JPA 实体的 Oracle OUT SYS_REFCURSOR 始终为空

在过程或函数中使用 SYS_REFCURSOR