DECLARE
TYPE record_AB IS RECORD
(
AA VARCHAR2 (16 BYTE),
BB VARCHAR2 (16 BYTE)
);
TYPE type_tab_AB IS TABLE OF record_AB
INDEX BY BINARY_INTEGER;
tab_AB type_tab_AB;
BEGIN
SELECT *
BULK COLLECT INTO tab_AB FROM...
..
SELECT * FROM TABLE (tab_AB) ;
当它从TABLE语句中获取SELECT时,我得到“ORA-22905:无法访问非嵌套表项的行”。
甚至可以在PLSQL中查询表类型吗?
答案 0 :(得分:28)
可以在PL / SQL中查询表类型,但只能查询其类型在模式级别(即PL / SQL之外)声明的嵌套表和变量。
错误
ORA-22905:无法访问非嵌套表项的行
表示您尝试从不受支持的表类型进行查询。由于type_tab_AB
子句,您的类型INDEX BY BINARY_INTEGER
是一个关联数组。删除INDEX BY BINARY_INTEGER
子句以使type_tab_AB
成为嵌套表类型。 (Varrays也可以在这里工作,但我不建议使用它们,除非你知道所期望的行数的上限。当声明一个varray类型时,你需要指定最大元素数,而嵌套表类型有没有这样的限制。)
进行此更改后,您的代码可能仍然无效。您可能会遇到的下一个错误(如果不这样,请参见底部的注释)
PLS-00642:SQL语句中不允许使用本地集合类型
这是因为您选择的类型是在PL / SQL中声明的。您需要使用type_tab_AB
在PL / SQL之外声明record_AB
和CREATE TYPE ...
。
您遇到的下一个问题是关键字RECORD
。记录类型只能在PL / SQL they cannot be created at schema level中创建。将RECORD
更改为OBJECT
以解决此问题。
您将遇到的最后一个问题是SELECT t.AA, t.BB BULK COLLECT INTO tab_AB FROM ...
语句。就目前而言,此查询将为您提供以下错误:
PL / SQL:ORA-00947:值不够
您正在从每行中选择两个项目,并且只提供一个表来批量插入数据。 Oracle无法确定您是否希望将这两个项填充到record_AB
类型中。您可以通过将查询更改为SELECT record_AB(t.AA, t.BB) BULK COLLECT INTO tab_AB FROM ...
来轻松解决此问题。
这些变化应该解决问题。这是一个完整的SQL * Plus脚本,它创建一个包含一些测试数据的测试表,并验证它是否可以查询表类型:
CREATE TABLE some_table (AA VARCHAR2(16 BYTE), BB VARCHAR2(16 BYTE));
INSERT INTO some_table (AA, BB) VALUES ('aa 1', 'bb 1');
INSERT INTO some_table (AA, BB) VALUES ('aaaaaaaaaa 2', 'b 2');
INSERT INTO some_table (AA, BB) VALUES ('aaaaa 3', 'bbbbbbbbbbbbbb 3');
COMMIT;
VARIABLE curs REFCURSOR;
CREATE OR REPLACE TYPE record_AB AS OBJECT
(
AA VARCHAR2 (16 BYTE),
BB VARCHAR2 (16 BYTE)
);
/
CREATE OR REPLACE TYPE type_tab_AB IS TABLE OF record_AB;
/
DECLARE
tab_AB type_tab_AB;
BEGIN
SELECT record_AB(t.AA, t.BB)
BULK COLLECT INTO tab_AB
FROM some_table t;
OPEN :curs FOR SELECT * FROM TABLE (tab_AB) ;
END;
/
PRINT :curs
我将SELECT
tab_AB
内容的结果放入游标,并使用SQL * Plus游标变量列出其内容。在所有“类型创建”和“PL / SQL过程成功完成”消息之后,在Oracle 11g XE上运行脚本时得到的输出如下:
AA BB
---------------- ----------------
aa 1 bb 1
aaaaaaaaaa 2 b 2
aaaaa 3 bbbbbbbbbbbbbb 3
注意:为简单起见,我假设提问者使用的是Oracle 11或更早版本。在Oracle 12中,我相信您可以在SQL查询中使用PL / SQL中声明的类型,因此您可能不会遇到PLS-00642错误。我不能说我对Oracle 12的其他修改也可能是必要的,因为我还没有使用Oracle 12。
答案 1 :(得分:2)
您无法查询在pl / sql块中创建的类型。您需要在sql提示符下创建它,然后您可以查询它。见下面的例子:
scott@ORA92> CREATE OR REPLACE TYPE emp_type AS OBJECT
2 (id NUMBER,
3 name VARCHAR2(20));
4 /
Type created.
scott@ORA92> CREATE OR REPLACE TYPE emp_tab AS TABLE OF emp_type;
2 /
Type created.
scott@ORA92> VARIABLE g_ref REFCURSOR
scott@ORA92> DECLARE
2 employees emp_tab := emp_tab();
3 BEGIN
4 employees.EXTEND(2);
5 employees(1) := emp_type (1, 'name1');
6 employees(2) := emp_type (2, 'name2');
7 OPEN :g_ref FOR
8 SELECT * FROM TABLE (CAST (employees AS emp_tab));
9 END;
10 /