3

我在 PL/SQL 包中创建了一个函数,该函数使用定义为数字表的自定义类型。我在带有 SELECT COLUMN_VALUE 指令的 SQL 查询中使用这种类型的对象,如下所示:

包中的类型定义:

type T_IDS is table of my_table.col_id%type;

包体中一个过程内的查询:

l_ids_list T_IDS ;
begin
select col_ids bulk collect into T_IDS from my_table;
select sum(t.rec_value) into total_value 
          from my_table t where t.col_id in (
            select column_value from Table(l_ids_list) );

一切正常,当我编译这段代码时,我可以看到在我的 schema_name/type 部分下生成了一个新类型。

一旦我在测试环境中安装了它,它就会导致编译失败并出现错误:

错误:PLS-00642:SQL 语句中不允许本地集合类型
错误:PL/SQL:ORA-22905:无法访问非嵌套表项中的行

数据库版本(本地和测试)完全相同,11g。有没有办法在 DBMS 上激活这样的一代?

重现的例子:

create table my_table (
col_id number,
rec_value number
);

insert into my_table (col_id, rec_value) values (1,100);
insert into my_table (col_id, rec_value) values (2,200);
insert into my_table (col_id, rec_value) values (3,300);
insert into my_table (col_id, rec_value) values (4,400);

commit;

包创建:

create or replace package test_pck as

type T_IDS is table of my_table.col_id%type;

procedure test_list;

end test_pck;
/

create or replace
package body test_pck as

procedure test_list is
  l_ids_list T_IDS ;
  total_value number;
begin
  select col_id bulk collect into l_ids_list from my_table;
  select sum(t.rec_value) into total_value 
            from my_table t where t.col_id in (
              select column_value from Table(l_ids_list) );
end test_list;
end test_pck;
/
4

1 回答 1

2

你在做什么是错的。您应该创建 SQL 类型,而不是使用 pl/sql 类型来访问该TABLE函数。

现在至于为什么它实际上在您的开发环境中起作用。

静默 pl/sql 表创建是为流水线函数设计的,并且已经存在了一段时间,但是您在非流水线函数中使用它,因此应该失败。但是,在 11g 第 1 版(准确地说是 11.1.0.7)中,一个错误意味着它实际上可以编译。如果你真的尝试运行它,虽然你会得到一个错误:

SQL> create package body foo
  2  as
  3
  4    procedure test
  5     is
  6             l_ids_list T_IDS ;
  7             total_value number;
  8     begin
  9             select col_id bulk collect into l_ids_list from my_table;
 10             select sum(t.rec_value) into total_value
 11               from my_table t
 12              where t.col_id in (select column_value from Table(l_ids_list));
 13     end;
 14  end;
 15  /

Package body created.

SQL> exec foo.test;
BEGIN foo.test; END;

*
ERROR at line 1:
ORA-21700: object does not exist or is marked for delete
ORA-06512: at "TEST.FOO", line 10
ORA-06512: at line 1
SQL> select * from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production
PL/SQL Release 11.2.0.2.0 - Production
CORE    11.2.0.2.0      Production
TNS for Linux: Version 11.2.0.2.0 - Production
NLSRTL Version 11.2.0.2.0 - Production

现在,Oracle 在 11.2.0.3 中修复了这个错误行为。现在在编译时抛出错误:

SQL> create package body foo
  2  as
  3
  4    procedure test
  5     is
  6             l_ids_list T_IDS ;
  7             total_value number;
  8     begin
  9             select col_id bulk collect into l_ids_list from my_table;
 10             select sum(t.rec_value) into total_value
 11               from my_table t
 12              where t.col_id in (select column_value from Table(l_ids_list));
 13     end;
 14  end;
 15  /

Warning: Package Body created with compilation errors.

SQL> show errors
Errors for PACKAGE BODY FOO:

LINE/COL ERROR
-------- -----------------------------------------------------------------
10/3     PL/SQL: SQL Statement ignored
12/48    PL/SQL: ORA-22905: cannot access rows from a non-nested table
         item

12/54    PLS-00642: local collection types not allowed in SQL statements
SQL> select * from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
PL/SQL Release 11.2.0.3.0 - Production
CORE    11.2.0.3.0      Production
TNS for Linux: Version 11.2.0.3.0 - Production
NLSRTL Version 11.2.0.3.0 - Production

简而言之,创建一个 SQL 类型create type并使用它来代替:

SQL> create type T_IDS as table of number;
  2  /

Type created.

SQL> create package body foo
  2  as
  3
  4    procedure test
  5     is
  6             l_ids_list T_IDS ;
  7             total_value number;
  8     begin
  9             select col_id bulk collect into l_ids_list from my_table;
 10             select sum(t.rec_value) into total_value
 11               from my_table t
 12              where t.col_id in (select column_value from Table(l_ids_list));
 13     end;
 14  end;
 15  /

Package body created.

SQL> exec foo.test

PL/SQL procedure successfully completed.

SQL> select * from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
PL/SQL Release 11.2.0.3.0 - Production
CORE    11.2.0.3.0      Production
TNS for Linux: Version 11.2.0.3.0 - Production
NLSRTL Version 11.2.0.3.0 - Production
于 2013-01-24T13:08:58.113 回答