2014-04-01 71 views
1

我有一個獲取元素列表並將它們放入表中的函數,這樣一個列表就可以用作綁定變量。一切工作正常,除了當我給列表USER列表中的元素,似乎Sql Developer做了一些解析並導致一些ORA-20001: comma-separated list invalid near T,USE錯誤。你知道是否可以爲此添加解決方法,以便該功能也可以與USER元素一起使用?在SQL Developer中綁定變量的列表

功能:

FUNCTION comma_to_table(iv_raw IN VARCHAR2) 
    RETURN bind_tab_typ 
    PIPELINED 
    IS 
    ltab_lname dbms_utility.lname_array; 
    ln_len  BINARY_INTEGER; 
    BEGIN 
    dbms_utility.comma_to_table(list => iv_raw 
           ,tablen => ln_len 
           ,tab => ltab_lname); 
    FOR i IN 1 .. ln_len LOOP 
     PIPE ROW (ltab_lname(i)); 
    END LOOP; 
    END comma_to_table; 

這裏是測試它的查詢:

select * from table(ui_util.comma_to_table(:myList)) 

如果myList中我把TEST,SUPPORT,USERT它的工作原理perfecly。如果我將其更改爲TEST,SUPPORT,USER,則會出現上述錯誤。任何建議?

+0

什麼類型是返回'bind_tab_typ'? –

回答

3

問題是dbms_utility.comma_to_table procedure要求列表中的元素是有效的Oracle標識符,儘管這在文檔中並沒有明確說明。 This AskTom article是指它雖然,通過底層name_tokenize procedure

注意,您不必使用真實對象的名稱(這些表和 程序不必存在),但你必須使用有效的對象 標識符。如果您不使用有效的對象標識符,則NAME_TOKENIZE將引發錯誤。

這不是綁定或SQL Developer,它是一個數據庫限制。

你可以看到相同類型的錯誤,如果你調用dbms_utility.comma_to_table程序直接:

declare 
    arr dbms_utility.uncl_array; 
    len binary_integer; 
begin 
    dbms_utility.comma_to_table('USER', len, arr); 
end; 
/

Error report - 
ORA-20001: comma-separated list invalid near R 
ORA-06512: at "SYS.DBMS_UTILITY", line 236 
ORA-06512: at "SYS.DBMS_UTILITY", line 256 
ORA-06512: at line 5 

或者通過直接調用dbms_utility.name_tokenize

declare 
    a varchar2(30); 
    b varchar2(30); 
    c varchar2(30); 
    d varchar2(30); 
    e binary_integer; 
begin 
    dbms_utility.name_tokenize('USER', a, b, c, d, e); 
end; 
/

Error report - 
ORA-00931: missing identifier 
ORA-06512: at "SYS.DBMS_UTILITY", line 167 
ORA-06512: at line 8 
00931. 00000 - "missing identifier" 

你不能,如果你的逗號使用分開的值是reserved words或由於某些其他原因不允許作爲標識符;例如,以數字開頭。如果列表中包含TABLE42TAB,則會出現同樣的問題。正如湯姆提到的,這並不是真正意圖的目的。

您可以通過強制所有元素被雙引號來部分解決限制,您可以使用replace來做到這一點。然後所有的這些例子被允許:

declare 
    arr dbms_utility.uncl_array; 
    len binary_integer; 
begin 
    dbms_utility.comma_to_table('"USER","TABLE","42TAB"', len, arr); 
end; 
/

anonymous block completed 

因此,對於你的代碼,修改iv_raw當你經過它跨越,然後從每個刪除雙引號返回值:

FUNCTION comma_to_table(iv_raw IN VARCHAR2) 
    RETURN bind_tab_typ 
    PIPELINED 
    IS 
    ltab_lname dbms_utility.lname_array; 
    ln_len  BINARY_INTEGER; 
    BEGIN 
    dbms_utility.comma_to_table(list => '"' || replace(iv_raw, ',', '","') || '"' 
           ,tablen => ln_len 
           ,tab => ltab_lname); 
    FOR i IN 1 .. ln_len LOOP 
     PIPE ROW (replace(ltab_lname(i), '"')); 
    END LOOP; 
    END comma_to_table; 

那麼這工作原理:

select * from table(ui_util.comma_to_table('USER,TABLE,42T')); 

COLUMN_VALUE 
-------------------- 
USER 
TABLE 
42T 

但你仍然受限於每一個元素是30個字符以內,因爲這是在偶數帶引號的標識符的限制。