2013-10-06 69 views
7
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:無法從非嵌套表項中訪問行」。ORA-22905 - 使用select語句查詢表類型時

查詢PLSQL中的表類型有沒有可能?

+0

我認爲這需要更多的上下文。你能發佈一個演示這個錯誤的_complete_最小的例子嗎?你必須在你的程序中用多個記錄填充'tab_AB',以便在這種情況下工作,在這種情況下你爲什麼要選擇這個變量。 – Ben

回答

23

它可以查詢在PL/SQL表類型,但只有嵌套表和可變數組,其類型在架構層面,即PL/SQL外部的聲明。

錯誤

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

意味着你正試圖從一個不表類型進行查詢。由於INDEX BY BINARY_INTEGER子句,您的類型type_tab_AB是一個關聯數組。刪除INDEX BY BINARY_INTEGER子句以使您的type_tab_AB爲嵌套表類型。 (Varrays也可以在這裏工作,但我不建議使用它們,除非你知道預期行數的上限。當聲明一個varray類型時,你需要指定最大元素數,而嵌套表類型有沒有這樣的限制。)

做出這一改變後,你的代碼可能仍然不起作用。下一個錯誤,你可能會得到(見注在底部,如果你不這樣做)是

PLS-00642: local collection types not allowed in SQL statements

這是因爲你選擇到類型PL/SQL中聲明。您需要在PL/SQL之外聲明type_tab_ABrecord_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: not enough values

您的選擇會從每排兩個項目和正在提供只有一個表中的數據批量插入。 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遊標變量來列出其內容。輸出當我運行的Oracle 11g XE劇本我得到的,畢竟和「PL/SQL過程已成功完成」的消息,在「創造型」的情況如下:

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

'但只嵌套表'不只是嵌套表。您也可以對變量數組SQL數據類型使用'table'運算符。 –

+1

@NicholasKrasnov:謝謝,我不知道。我已經更新了我的答案,提到varrays。我不能說我之前已經使用了varrays,我不認爲它們在這裏工作得特別好。這個Oracle錯誤消息意味着只有嵌套表與'TABLE'運算符一起工作是一件令人遺憾的事情。 –

+0

我使用的是oracle 12和11,剛剛遇到這個錯誤的移植應用程序從12到11嘗試從規範級別聲明的表類型中選擇。謝謝! –

2

您無法查詢在pl/sql塊內創建的類型。你需要在sql提示符下創建它,然後你可以查詢它。參見〔實施例如下:

[email protected]> CREATE OR REPLACE TYPE emp_type AS OBJECT 
    2 (id NUMBER, 
    3  name VARCHAR2(20)); 
    4/

Type created. 

[email protected]> CREATE OR REPLACE TYPE emp_tab AS TABLE OF emp_type; 
    2/

Type created. 

[email protected]> VARIABLE g_ref REFCURSOR 
[email protected]> 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/