如何正确地将此过程转换为PLSQL块?参考未初始化的功能

时间:2017-02-08 17:05:22

标签: sql oracle plsql

以下块正确编译。(不重要的部分已编辑)

CREATE OR REPLACE PROCEDURE testProc
IS
TYPE test_h IS TABLE OF VARCHAR2(100) INDEX BY VARCHAR2(100);
test_h_list test_h;
TYPE l_ids IS TABLE OF VARCHAR(100);
l_id_list l_ids;

BEGIN 
  test_h_list('A'):='Apple'; 
  test:=test_h_list.FIRST;
  WHILE test IS NOT NULL LOOP
    BEGIN
    SELECT  tbl1.l_id BULK COLLECT INTO l_id_list
    WHERE ....
    ....
    ....
  END;

但是,当我尝试将其转换为plsql块时

DECLARE
TYPE test_h IS TABLE OF VARCHAR2(100) INDEX BY VARCHAR2(100); 
test_h_list test_h; --ORA-06531: Reference to uninitialized collection  :-(
TYPE l_ids IS TABLE OF VARCHAR(100);
l_id_list l_ids;

BEGIN 
  test_h_list('A'):='Apple'; 
  test:=test_h_list.FIRST;
  WHILE test IS NOT NULL LOOP
    BEGIN
    SELECT  tbl1.l_id BULK COLLECT INTO l_id_list
    WHERE ....
    ....
    ....
  END;

我在上面注释了'ORA-06531:未初始化集合的引用'错误。我尝试了搜索this并基于示例here

我想出了这个

DECLARE
TYPE test_h IS TABLE OF VARCHAR2(100) INDEX BY VARCHAR2(100); 
test_h_list test_h := test_h();
TYPE l_ids IS TABLE OF VARCHAR(100);
l_id_list l_ids :=l_ids();


BEGIN 
  test_h_list.EXTEND(100);
  l_ids.EXTEND(100);
  test_h_list('A'):='Apple'; 
  test:=test_h_list.FIRST;
  WHILE test IS NOT NULL LOOP
    BEGIN
    SELECT  tbl1.l_id BULK COLLECT INTO l_id_list
    WHERE ....
    ....
    ....
  END;

但是这会抛出一个错误,说PLS-00222:此范围内不存在名称为'test_h'的函数。关于我可能缺少什么的任何想法?

MCVE

脚本 -

DECLARE
TYPE test_h IS TABLE OF VARCHAR2(100) INDEX BY VARCHAR2(100);
test_h_list test_h := test_h(); --Line 3
TYPE l_ids IS TABLE OF VARCHAR(100);
l_id_list l_ids := l_ids();
test_str VARCHAR(50);

BEGIN 
  test_h_list.EXTEND(100);
  l_id_list.EXTEND(100);
  test_h_list('App'):='1'; 
  test_h_list('Red'):='2'; 
  test_str:=test_h_list.FIRST;
  WHILE test_str IS NOT NULL LOOP
    BEGIN
    SELECT  TABLE1.DEPT  BULK COLLECT INTO l_id_list
    FROM    TABLE1
    WHERE   TABLE1.NAME = test_str;

    FOR indx IN 1..l_id_list.COUNT
      LOOP

                         DBMS_OUTPUT.PUT_LINE( l_id_list(indx));


      END LOOP;
    test_str:=test_h_list.NEXT(test_str);
    EXCEPTION
    WHEN OTHERS THEN -- Just print  the failure to logs
           NULL;

    END;
  END LOOP;
END; 
/

错误报告 -

Error starting at line 1 in command:
DECLARE
TYPE test_h IS TABLE OF VARCHAR2(100) INDEX BY VARCHAR2(100);
test_h_list test_h := test_h();
TYPE l_ids IS TABLE OF VARCHAR(100);
l_id_list l_ids := l_ids();
test_str VARCHAR(50);

BEGIN 
  test_h_list.EXTEND(100);
  l_id_list.EXTEND(100);
  test_h_list('App'):='1'; 
  test_h_list('Red'):='2'; 
  test_str:=test_h_list.FIRST;
  WHILE test_str IS NOT NULL LOOP
    BEGIN
    SELECT  TABLE1.DEPT  BULK COLLECT INTO l_id_list
    FROM    TABLE1
    WHERE   TABLE1.NAME = test_str;

    FOR indx IN 1..l_id_list.COUNT
      LOOP

                         DBMS_OUTPUT.PUT_LINE( l_id_list(indx));


      END LOOP;
    test_str:=test_h_list.NEXT(test_str);
    EXCEPTION
    WHEN OTHERS THEN 
           NULL;

    END;
  END LOOP;
END; 
Error report:
ORA-06550: line 3, column 23:
PLS-00222: no function with name 'TEST_H' exists in this scope
ORA-06550: line 3, column 13:
PL/SQL: Item ignored
ORA-06550: line 9, column 3:
PLS-00320: the declaration of the type of this expression is incomplete or malformed
ORA-06550: line 9, column 3:
PL/SQL: Statement ignored
ORA-06550: line 11, column 3:
PLS-00320: the declaration of the type of this expression is incomplete or malformed
ORA-06550: line 11, column 3:
PL/SQL: Statement ignored
ORA-06550: line 12, column 3:
PLS-00320: the declaration of the type of this expression is incomplete or malformed
ORA-06550: line 12, column 3:
PL/SQL: Statement ignored
ORA-06550: line 13, column 13:
PLS-00320: the declaration of the type of this expression is incomplete or malformed
ORA-06550: line 13, column 3:
PL/SQL: Statement ignored
ORA-06550: line 27, column 15:
PLS-00320: the declaration of the type of this expression is incomplete or malformed
ORA-06550: line 27, column 5:
PL/SQL: Statement ignored
06550. 00000 -  "line %s, column %s:\n%s"
*Cause:    Usually a PL/SQL compilation error.
*Action:
Elapsed: 00:00:00.011

1 个答案:

答案 0 :(得分:1)

在你的MCVE中,你混合了不同类型的PL / SQL表。您的dotnet.exe类型已编入索引,因此无需初始化且无法扩展 - 因为它是稀疏表类型。因此,删除test_h:= test_h()行会使其有效:

extend

你原来的第一个匿名块没有执行其中任何一个,并且DECLARE TYPE test_h IS TABLE OF VARCHAR2(100) INDEX BY VARCHAR2(100); test_h_list test_h; -- do no instantiate := test_h(); --Line 3 TYPE l_ids IS TABLE OF VARCHAR(100); l_id_list l_ids := l_ids(); test_str VARCHAR(50); BEGIN -- test_h_list.EXTEND(100); -- do not extend either l_id_list.EXTEND(100); test_h_list('App'):='1'; test_h_list('Red'):='2'; test_str:=test_h_list.FIRST; WHILE test_str IS NOT NULL LOOP BEGIN SELECT TABLE1.DEPT BULK COLLECT INTO l_id_list FROM TABLE1 WHERE TABLE1.NAME = test_str; FOR indx IN 1..l_id_list.COUNT LOOP DBMS_OUTPUT.PUT_LINE( l_id_list(indx)); END LOOP; test_str:=test_h_list.NEXT(test_str); EXCEPTION WHEN OTHERS THEN -- Just print the failure to logs NULL; END; END LOOP; END; / PL/SQL procedure successfully completed. 具有相同的稀疏表类型,所以不应该得到ORA-06531。如果你从类型定义中删除了test_h,你就会看到它,但那并不是你所展示的。

你也可以尝试引用INDEX BY VARCHAR2(100)的元素而不初始化它 - 但正如问题所示,它总是被循环中的批量收集隐含地初始化,即使被查询的真实表是空的 - 你只有一个空的PL / SQL表。

您最初展示的代码不会抛出错误;并且MCVE正在做一些不同的事情,离第二个匿名区块比第一个更接近。