You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用自定义集合的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

火山引擎 最新活动