【问题标题】:getting "comma-separated list near 'xx.yy' invalid" with dbms_utility.comma_to_table使用 dbms_utility.comma_to_table 获取“'xx.yy' 附近的逗号分隔列表无效”
【发布时间】:2014-12-04 01:35:22
【问题描述】:

我有这样的字符串:str:='ac_Abc.88,ac_Abc.99,ac_Abc.77'。我需要在用逗号(,)拆分后获取第一个元素。所以我像这样使用:

str VARCHAR2(500);
dbms_utility.comma_to_table
      ( list   => regexp_replace(str,'(^|,)','\1')
      , tablen => l_count
      , tab    => l_array
     ); 

我收到以下错误:

ORA-20001: comma-separated list invalid near bc.88
ORA-06512: at "SYS.DBMS_UTILITY", line 239
ORA-06512: at "SYS.DBMS_UTILITY", line 272

但如果我有这样的字符串,str:='ac_Abc88,ac_Abc99,ac_Abc77',同样的方法可以正常工作并给我预期的结果。

所以我想有一些事情需要更正才能考虑“。”作为常规字符。你能建议我如何解决这个问题吗?

【问题讨论】:

    标签: sql oracle plsql string-split


    【解决方案1】:

    How to split comma delimited string into rows

    1. REGEXP_SUBSTR 方法

    SQL> WITH DATA AS(
      2  SELECT 'ac_Abc.88,ac_Abc.99,ac_Abc.77' str FROM dual)
      3  SELECT regexp_substr(str,'[^,]+',1,level) str
      4  FROM DATA
      5    CONNECT BY regexp_substr(str, '[^,]+', 1, level) IS NOT NULL
      6  /
    
    STR
    -----------------------------
    ac_Abc.88
    ac_Abc.99
    ac_Abc.77
    
    SQL>
    

    2。 XML 方法

    SQL> SELECT EXTRACT (VALUE (d), '//row/text()').getstringval () str
      2  FROM
      3    (SELECT XMLTYPE ( '<rows><row>'
      4      || REPLACE ('ac_Abc.88,ac_Abc.99,ac_Abc.77', ',', '</row><row>')
      5      || '</row></rows>' ) AS xmlval
      6    FROM DUAL
      7    ) x,
      8    TABLE (XMLSEQUENCE (EXTRACT (x.xmlval, '/rows/row'))) d
      9  /
    
    STR
    --------------------
    ac_Abc.88
    ac_Abc.99
    ac_Abc.77
    

    3.表函数

    SQL> CREATE TYPE test_type
      2  AS
      3    TABLE OF VARCHAR2(100)
      4  /
    
    Type created.
    
    SQL>
    SQL> CREATE OR REPLACE
      2  FUNCTION comma_to_table(
      3      p_list IN VARCHAR2)
      4    RETURN test_type
      5  AS
      6    l_string VARCHAR2(32767) := p_list || ',';
      7    l_comma_index PLS_INTEGER;
      8    l_index PLS_INTEGER := 1;
      9    l_tab test_type     := test_type();
     10  BEGIN
     11    LOOP
     12      l_comma_index := INSTR(l_string, ',', l_index);
     13      EXIT
     14    WHEN l_comma_index = 0;
     15      l_tab.EXTEND;
     16      l_tab(l_tab.COUNT) := SUBSTR(l_string, l_index, l_comma_index - l_index);
     17      l_index            := l_comma_index                           + 1;
     18    END LOOP;
     19    RETURN l_tab;
     20  END comma_to_table;
     21  /
    
    Function created.
    
    SQL> sho err
    No errors.
    SQL>
    SQL> SELECT * FROM TABLE(comma_to_table('ac_Abc.88,ac_Abc.99,ac_Abc.77'))
      2  /
    
    COLUMN_VALUE
    --------------------------------------------------------------------------------
    ac_Abc.88
    ac_Abc.99
    ac_Abc.77
    
    SQL>
    

    4.流水线函数

    SQL> CREATE OR REPLACE
      2    FUNCTION comma_to_table(
      3        p_list IN VARCHAR2)
      4      RETURN test_type PIPELINED
      5    AS
      6      l_string LONG := p_list || ',';
      7      l_comma_index PLS_INTEGER;
      8      l_index PLS_INTEGER := 1;
      9    BEGIN
     10      LOOP
     11        l_comma_index := INSTR(l_string, ',', l_index);
     12        EXIT
     13      WHEN l_comma_index = 0;
     14        PIPE ROW ( SUBSTR(l_string, l_index, l_comma_index - l_index) );
     15        l_index := l_comma_index                           + 1;
     16      END LOOP;
     17      RETURN;
     18    END comma_to_table;
     19    /
    
    Function created.
    
    SQL> sho err
    No errors.
    SQL>
    SQL> SELECT * FROM TABLE(comma_to_table('ac_Abc.88,ac_Abc.99,ac_Abc.77'))
      2  /
    
    COLUMN_VALUE
    --------------------------------------------------------------------------------
    ac_Abc.88
    ac_Abc.99
    ac_Abc.77
    

    【讨论】:

    • Oracle 正则表达式默认“贪婪”的精美演示。
    • @nop77svk,Tom Kyte 的著名comma_to_table 也是一个不错的选择。
    • 谢谢,可以看看,虽然我通常自己编写这些小东西。
    • @nop77svk,我在回答中添加了一个演示。
    • 您的演示使用了dbms_utility.comma_to_table(),由于点 (.) 和数字,它在原始问题中不起作用。
    【解决方案2】:

    因为(Oracle doc reference)

    COMMA_TO_TABLE 过程

    这些过程将逗号分隔的名称列表转换为 PL/SQL 名称表。第二个版本支持全限定 属性名称。

    这里提到的“名称”是一个有效的 Oracle(数据库对象)标识符,所有命名规则都适用于此。 ac_Abc.88 不是一个有效的名称,因为在 Oracle 中你不能有一个以数字开头的标识符。

    要解决解析逗号分隔值字符串的问题,请使用 Lalit Kumar B 的解决方案。

    【讨论】:

    • 是的,Lalit 的解决方案奏效了。由于声誉较低,无法投票。你能代表我投票吗.. :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-06
    • 2013-07-03
    • 1970-01-01
    • 2015-10-01
    • 1970-01-01
    • 2015-01-01
    • 2020-09-03
    相关资源
    最近更新 更多