自动类型生成
Posted
技术标签:
【中文标题】自动类型生成【英文标题】:Automatic type generation 【发布时间】:2013-01-24 08:35:17 【问题描述】:我在 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;
/
【问题讨论】:
你的意思是两个数据库都是 11.2 即 select * from v$version 是一样的?你是在测试中编译的还是通过从 Dev 导出/导入创建的? 查看不同版本后,不编译的是11.2.0.3版本,编译的是11.2.0.1版本。源代码直接在 DB 上编译,不使用导出安装 【参考方案1】:你做错了。您应该创建 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
简而言之,使用create type
创建一个 SQL 类型并改用它:
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
【讨论】:
是的,SQL 类型解决了编译问题。但我不明白的是,11.2.0.1 版本生成了一个全局类型(你称之为 SQL 类型),其结构与我的 PL/SQL 类型相同,但不是 11.2.0.3,这让我想到了一个配置问题.再次感谢您 @HADDARMohamed 不,这不是配置问题。就像我说的,这是 11.1.0.7-11.2.0.2 中的一个 BUG,这意味着类型已生成并且编译成功。两者都不应该发生。如果您有 Oracle 支持访问权限,请查找“错误 9383293 - PL/SQL 块内的 SQL 语句中使用的 PL/SQL 表类型变量在运行时而不是编译时失败 [ID 9383293.8]”以上是关于自动类型生成的主要内容,如果未能解决你的问题,请参考以下文章
使用 OData 生成器生成类型化 OData 客户端:自动生成的代码无法与 SAP 库一起编译