【问题标题】:Oracle error ORA-22905: cannot access rows from a non-nested table itemOracle 错误 ORA-22905: 无法访问非嵌套表项中的行
【发布时间】:2018-04-30 17:19:41
【问题描述】:

这是我编写的存储过程。在这个过程中,“p_subjectid”是一个从前端传递的数字数组。

PROCEDURE getsubjects(p_subjectid subjectid_tab,p_subjects out refCursor) 
       as

       BEGIN

            open p_subjects for select * from empsubject where subject_id in
            (select column_value from table(p_subjectid));
            --select * from table(cast(p_subjectid as packg.subjectid_tab))
      END getsubjects;

这是我遇到的错误。

Oracle error ORA-22905: cannot access rows from a non-nested table item OR

正如我在不同的帖子中看到的那样,我尝试在表函数中强制转换“cast(p_subjectid as packg.subjectid_tab)”,如下面的评论中给出的那样。但我收到另一个错误:ORA-00902: invalid datatype

这就是“subjectid_tab”的定义。

type subjectid_tab is table of number index by binary_integer;

谁能告诉我错误是什么。我的程序有什么问题吗。

【问题讨论】:

    标签: oracle10g


    【解决方案1】:

    您必须按照 ammoQ 的建议在“数据库级别”声明类型:

    CREATE TYPE subjectid_tab AS TABLE OF NUMBER INDEX BY binary_integer;
    

    而不是在 PL/SQL 中声明类型。如果只在 PL/SQL 块中声明类型,SQL“引擎”将无法使用它。

    【讨论】:

    • 这在 Oracle 11g 中不起作用,以防其他人在苦苦挣扎。PLS-00355:在此上下文中未定义使用 pl/sql 表。不过,Oracle 12c 中的一切看起来都不错。作为 11g 中的一种解决方法,如果您只能绑定到关联数组(如 nodejs),我首先将关联数组循环到嵌套表中(无 INDEX BY 后缀);这会扼杀性能,但你能做什么?如果有人知道更好的方法,请随时与我们联系。
    • 这个答案一半正确一半错误 - TYPE ... AS TABLE OF ... INDEX BY ... 是关联数组和 PL/SQL 数据类型 - 它不能在 SQL 范围内使用,也不能使用 CREATE TYPE 定义但是您在 SQL 语句中使用类型是正确的,该类型需要在 SQL 范围而不是 PL/SQL 范围中定义(它只是一个关联数组不起作用)。
    【解决方案2】:

    Oracle 有两个执行范围:SQL 和 PL/SQL。当您使用SELECT/INSERT/UPDATE (etc) 语句时,您正在 SQL 范围内工作,并且在 Oracle 11g 及更低版本中,您不能引用在 PL/SQL 范围内定义的类型。 (注意:Oracle 12 对此进行了更改,因此您可以引用 PL/SQL 类型。)

    TYPE subjectid_tab IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
    

    是一个关联数组,只能在PL/SQL范围内定义,所以不能在SQL语句中使用。

    您想要的是在 SQL 范围内定义一个集合(不是关联数组),使用:

    CREATE TYPE subjectid_tab IS TABLE OF NUMBER;
    

    (注意:集合不需要INDEX BY 子句。)

    那么你可以这样做:

    OPEN p_subjects FOR
      SELECT *
      FROM   empsubject
      WHERE  subject_id MEMBER OF p_subjectid;
    

    OPEN p_subjects FOR
      SELECT *
      FROM   empsubject
      WHERE  subject_id IN ( SELECT COLUMN_VALUE FROM TABLE( p_subjectid ) );
    

    【讨论】:

      【解决方案3】:

      这是一个很好的解决方案。 如果您转换的类型在 pl/sql 块的 DECLARE 部分中,则不能使用 table(cast())。 你真的需要使用 CREATE TYPE my_type [...]。否则会抛出“cannot fetch row[...]”异常。

      【讨论】:

      • 这是答案的一半——不幸的是,您不能在 SQL 范围内将 CREATE TYPE 与关联数组 (AS TABLE OF ... INDEX BY ...) 一起使用,因为它是一种 PL/SQL 数据类型。您还需要删除 INDEX BY 子句,以便类型是一个集合(而不是关联数组)。
      【解决方案4】:

      我昨天刚遇到这个问题。

      宣布 类型 number_table 是数字表; result_ids number_table := number_table(); 开始 /* .. 一堆成功使用我的类型的代码 */ 打开 ?作为 选择 * FROM TABLE(CAST(result_ids AS number_table)); /* 轰! */ 结尾;

      当从 java 例程调用时,这两种方式都失败了。我发现这是因为 number_table 类型没有以可导出的方式定义,不能从数据库中运出。该类型在例程内部工作得很好。但是,一旦您尝试执行以任何方式引用它的可返回记录集(包括 IN 子句?!?),您就会得到一个未定义的数据类型。

      所以解决方案确实是CREATE TYPE myschema.number_table IS TABLE OF NUMBER; 然后从块中删除类型声明并使用模式级别声明。使用模式限定符来引用类型,以确保您使用的是正确的。

      【讨论】:

        【解决方案5】:

        您必须将流水线查询的结果转换为:

        如果您的流水线函数返回 varchar2 的行类型,则定义一个类型(例如)

        CREATE OR REPLACE TYPE char_array_t is VARRAY(32) of varchar2(255);
        select * from table(cast(fn(x) as user_type_t ) );
        

        现在可以工作了。

        【讨论】:

          猜你喜欢
          • 2020-11-29
          • 2018-09-05
          • 1970-01-01
          • 1970-01-01
          • 2021-08-04
          • 2020-02-11
          • 1970-01-01
          • 1970-01-01
          • 2018-08-19
          相关资源
          最近更新 更多