我有一个获取元素列表并将它们放入表中的函数,这样一个列表可以用作绑定变量。一切正常,除非我在列表USER
中作为元素提供,似乎Sql Developer进行了一些解析并导致一些ORA-20001: comma-separated list invalid near T,USE
错误。你知道是否可以为此添加一个解决方法,这样该函数也可以与USER
元素一起使用?
功能:
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
它完全正常。如果我将其更改为TEST,SUPPORT,USER
,我会收到上述错误。有什么建议吗?
答案 0 :(得分:4)
问题在于dbms_utility.comma_to_table
procedure要求列表中的元素是有效的Oracle标识符,尽管在文档中并没有明确说明。 This AskTom article通过底层name_tokenize
procedure:
请注意,您不必使用REAL对象名称(这些表和 过程不必存在)但您必须使用VALID对象 身份标识。如果您不使用有效的对象标识符, 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或由于某些其他原因而不允许作为标识符,则无法使用此功能;例如,以数字开头。如果列表包含TABLE
或42TAB
,您会遇到同样的问题。正如汤姆所提到的,这并非如此。
您可以通过强制所有元素进行双引号来部分解决这些限制,您可以使用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个字符,因为这是对引用标识符的限制。