带有游标的 pl/sql 可变数组

Posted

技术标签:

【中文标题】带有游标的 pl/sql 可变数组【英文标题】:pl/sql varray with a cursor 【发布时间】:2013-03-01 20:55:16 【问题描述】:

谁能告诉我这段代码有什么问题。我的目标是编写一个传递员工姓名的程序,将员工表中的所有姓名和薪水加载到 VARRAY 中,然后在屏幕上打印出姓名和薪水。

CREATE OR REPLACE PROCEDURE VARRAY_Q2 
(
  PNAME IN VARCHAR2  
, PSAL OUT NUMBER  
) AS 

--declare and create cursor

CURSOR emp_cur IS
SELECT ename,sal
FROM EMP;

  TYPE varray_emp IS VARRAY(14) OF emp_Cur%ROWTYPE;

  --Creating new instance of varray
  x_varray_emp varray_emp := varray_emp();
  v_counter NUMBER := 0;

BEGIN

  x_varray_emp.EXTEND;

  FOR empRecs IN emp_Cur LOOP

  --Insert data into the varray
  x_varray_emp(v_counter) := empRecs;

  dbms_output.put_line(v_counter);

  v_counter := v_counter + 1;
  END LOOP;

  --Loop through the varray and print out all the elements
  FOR i IN x_varray_emp.FIRST .. x_varray_emp.LAST 
  LOOP
  dbms_output.put_line(x_varray_emp(i));    
  END LOOP;

END;

【问题讨论】:

1.如果不使用任何参数,为什么要将它们传递给过程? 2. 当您可以直接在光标循环中进行操作时,为什么还要使用 VARRAY? 3. 如果你没有看到输出,你可能想要'set serveroutput on'。 你遇到了什么错误? @Glenn 我认为他正在学习如何做到这一点,并且在他弄清楚这部分之后将使用参数和 varray。 @Glenn:是的,我正在学习 pl/sql,我必须使用 varray。 感谢大家的帮助。 【参考方案1】:

首先:PL/SQL 集合不是基于 0 的。这将引发下标超出限制错误,因为您的计数器盯着 0。您也不需要此解决方案的计数器。如果您想继续使用它,请参阅第一个示例。但如果我是你,我会使用第二个例子。

其次,您在循环之前扩展了 varray。这将引发超出计数错误的下标,因为 varray 仅扩展为容纳一行。您需要在循环开始时对其进行扩展,以便在每次迭代时扩展 varray。

你不能PUT_LINE 一个完整的变量。您必须 put_line 可变数组中的元素。所以在这个例子中,而不是dbms_output.put_line(x_varray_emp(i)) 使用这个:dbms_output.put_line(x_varray_emp(i).ename || ' makes $' || x_varray_emp(i).sal)

第四:如果你的emp表中有超过14条记录,你的VARRAY(14)会导致下标超出限制错误。可变数组为它们设置了最大大小(有界限制),在您的情况下为 14。在此示例中,我将使用常规嵌套表(TYPE nested_emp IS TABLE OF emp_cur%ROWTYPE),以免担心有界限制(从技术上讲,嵌套表的最大值为 2147483647 aka PLS_INTEGER)。如果您愿意使用 NT 而不是 VA,请改用下面的第三种解决方案。

执行以下操作,它将起作用。

将您的v_counter NUMBER := 0 更改为v_counter NUMBER := 1

将 BODY 中的内容更改为:

BEGIN
    FOR empRecs IN emp_Cur LOOP
        x_varray_emp.EXTEND;
        --Insert data into the varray 
        x_varray_emp(v_counter) := empRecs;

        dbms_output.put_line(v_counter);

        v_counter := v_counter + 1; 
    END LOOP;
    --Loop through the varray and print out all the elements 
    FOR i IN x_varray_emp.FIRST .. x_varray_emp.LAST LOOP 
        dbms_output.put_line(x_varray_emp(i).ename || ' Makes $' || x_varray_emp(i).sal);
    END LOOP;
END;

实际上,您不需要计数器。如果您愿意放弃它,请改用 varray 的 COUNT 方法:

BEGIN


    FOR empRecs IN emp_Cur LOOP
        x_varray_emp.EXTEND;

        --Insert data into the varray 
        x_varray_emp(x_varray_emp.count) := empRecs;

        dbms_output.put_line(x_varray_emp.count);


    END LOOP;

    --Loop through the varray and print out all the elements 
    FOR i IN x_varray_emp.FIRST .. x_varray_emp.LAST LOOP 
        dbms_output.put_line(x_varray_emp(i).ename || ' Makes $' || x_varray_emp(i).sal);
    END LOOP;


END;

我希望您使用嵌套表来解决这个问题,而不是使用可变数组。如果你愿意,这里是解决方案:

DECLARE

    CURSOR emp_cur IS SELECT ename,sal FROM EMP;
    TYPE nestedtable_emp IS TABLE OF emp_cur%ROWTYPE;

    x_nestedtable_emp nestedtable_emp := nestedtable_emp();
BEGIN


    FOR empRecs IN emp_Cur LOOP
        x_nestedtable_emp.EXTEND;

        --Insert data into the varray 
        x_nestedtable_emp(x_nestedtable_emp.count) := empRecs;

        dbms_output.put_line(x_nestedtable_emp.count);


    END LOOP;

    --Loop through the varray and print out all the elements 
    FOR i IN x_nestedtable_emp.FIRST .. x_nestedtable_emp.LAST LOOP 
        dbms_output.put_line(x_varray_emp(i).ename || ' Makes $' || x_varray_emp(i).sal);
    END LOOP;


END;

【讨论】:

如果我们使用嵌套表 BULK COLLECT 会是更好的方法。但是这个任务不需要任何类型的集合:只需要一个简单的 FOR CURSOR 循环。这只是证明了这种家庭作业的无用性:它们教的是语言的机制,而不是如何正确使用它。所以学生真正学到的只是如何编写糟糕的 PL/SQL。

以上是关于带有游标的 pl/sql 可变数组的主要内容,如果未能解决你的问题,请参考以下文章

Oracle PL/SQL:如何使用可变数组作为输出参数执行过程?

SQL记录-PLSQL数组

在 plsql 可变数组中使用对象

在 PL/SQL 中将游标数据提取到数组中

Pl/Sql 在for循环中打开游标

Oracle之数组