使用自定义集合的PL/SQL函数触发ORA-00902无效数据类型错误求助
解决ORA-00902: invalid datatype错误的方案
嘿,这个ORA-00902的问题我太熟了,核心原因其实很简单:SQL引擎无法识别包内部定义的自定义集合类型。
你看,你的RowIDTable是定义在test_package包里面的类型,当你在DELETE语句里用TABLE(row_ids)的时候,这段SQL是跑在SQL引擎上下文里的,而包级别的类型只在PL/SQL引擎里可见,SQL根本不知道这个类型是什么,自然就抛出"invalid datatype"的错误了。
修复步骤:
先创建数据库级别的集合类型
你得把集合类型移到数据库层面创建,这样SQL和PL/SQL引擎都能访问到它:CREATE OR REPLACE TYPE RowIDTable IS TABLE OF VARCHAR2(500); / CREATE OR REPLACE TYPE IDTable IS TABLE OF test_table.id%TYPE; /修改包定义,使用数据库级别的类型
把包里原来的类型定义删掉,直接引用刚才创建的数据库级类型就行:CREATE OR REPLACE PACKAGE test_package IS FUNCTION delete_rows (row_ids IN RowIDTable) RETURN IDTable; END test_package; /可选优化:用原生ROWID类型提升效率
其实ROWID本身有Oracle原生的ROWID类型,没必要转成VARCHAR2,你可以把集合类型改成TABLE OF ROWID,这样既省去转换步骤,还能提升性能:
先更新数据库类型:CREATE OR REPLACE TYPE RowIDTable IS TABLE OF ROWID; /然后修改包体的DELETE语句,去掉
ROWIDTONCHAR转换:CREATE OR REPLACE PACKAGE BODY test_package IS FUNCTION delete_rows (row_ids IN RowIDTable) RETURN IDTable IS ids IDTable; BEGIN DELETE FROM test_table WHERE ROWID IN (SELECT * FROM TABLE(row_ids)) RETURNING id BULK COLLECT INTO ids; COMMIT; RETURN ids; END; END test_package; /
为什么这样能解决问题?
数据库级别的类型是存在数据字典里的,所有引擎都能识别,当你在DELETE语句中使用TABLE(row_ids)时,SQL引擎就能正确解析这个集合类型,不会再报错啦。
要是你用的是Oracle 12c及以上版本,还可以试试SQL_MACRO来简化,但上面的方案是最通用的,兼容所有支持集合类型的Oracle版本。
内容的提问来源于stack exchange,提问作者bobothewise




