Oracle-分割字符串逗号分隔(字符串包含空格和连续逗号)

时间:2016-02-16 22:28:22

标签: sql oracle plsql split

我无法找到有关如何在ORACLE中拆分逗号分隔字符串的解决方案。搜索了很多,没有什么适用于我的案例

代码

DECLARE
  TYPE T_ARRAY_OF_VARCHAR IS TABLE OF VARCHAR2(2000) INDEX BY BINARY_INTEGER;
  MY_ARRAY T_ARRAY_OF_VARCHAR;
  MY_STRING VARCHAR2(2000) := '12 3,456,,abc,def';
BEGIN
 FOR CURRENT_ROW IN (
    with test as    
      (select MY_STRING from dual)
      select regexp_substr(MY_STRING, '[^,]+', 1, rownum) SPLIT
      from test
      connect by level <= length (regexp_replace(MY_STRING, '[^,]+'))  + 1)

  LOOP
   DBMS_OUTPUT.PUT_LINE('>' || CURRENT_ROW.SPLIT || '<');
   --DBMS_OUTPUT.PUT_LINE(CURRENT_ROW.SPLIT);
    MY_ARRAY(MY_ARRAY.COUNT) := CURRENT_ROW.SPLIT;
  END LOOP;

  DBMS_OUTPUT.PUT_LINE('Array Size:' || MY_ARRAY.COUNT);
END;

/

输出结果为:

>12 3<
>456<
>abc<
>def<
><
Array Size:5

空值无序!!!!

4 个答案:

答案 0 :(得分:7)

尝试这个来解析列表部分。它处理NULLS:

SQL> select regexp_substr('12 3,456,,abc,def', '(.*?)(,|$)', 1, level, null, 1) SPLIT, level
    from dual
    connect by level <= regexp_count('12 3,456,,abc,def',',') + 1
    ORDER BY level;

SPLIT                  LEVEL
----------------- ----------
12 3                       1
456                        2
                           3
abc                        4
def                        5

SQL>

不幸的是,当您搜索正则表达式来解析列表时,您总会发现此表单不处理空值,应该避免使用:'[^,]+'。有关详细信息,请参阅此处:Split comma separated values to columns in Oracle

答案 1 :(得分:3)

尝试xmltable和flwor expresion。 如果您输入不带逗号的字符串,以下示例不安全并抛出错误。但更容易理解。

select xmlcast(column_value as varchar2(2000))  value_list 
  from xmltable('for $val in ora:tokenize($strList,",") 
                  return $val' 
                 passing '12 3,456,,abc,def' as "strList"
                ); 

安全版。

    select xmlcast(column_value as varchar2(2000)) value_list 
      from xmltable('for $val at $index in ora:tokenize(concat(",",$strList),",") 
       where $index > 1 
       return $val' passing '12 3,456,,abc,def' as "strList"
               );

答案 2 :(得分:2)

对您的查询进行少许修改,假设您可以选择一个不会出现在MY_STRING中的字符,例如管|

   with test as    
  (select '12 3,456,,,,abc,def' MY_STRING from dual)
  select trim('|' from regexp_substr(regexp_replace(MY_STRING,',,',',|,|'),'[^,]+',1,level)) SPLIT
  from test
  connect by level <= length (regexp_replace(MY_STRING, '[^,]+'))  + 1;

输出:

 SPLIT                 
-----------------------
12 3                    
456                     
(null)                        
(null)                         
(null)                         
abc                     
def  

答案 3 :(得分:2)

不需要 PL / SQL ,您可以在纯 SQL 中执行此操作。请参阅Split comma delimited strings in a table in Oracle

使用 MODEL 子句:

WITH sample_data AS (
SELECT '12 3,456,,,,,abc,def' str FROM dual
)
-- end of sample_data mimicking real table
,
model_param AS (
SELECT str AS orig_str ,
       ','
       || str
       || ','                                 AS mod_str ,
       1                                      AS start_pos ,
       Length(str)                           AS end_pos ,
       (LENGTH(str) -
       LENGTH(REPLACE(str, ','))) + 1        AS element_count ,
       0                                      AS element_no ,
       ROWNUM                                 AS rn
       FROM   sample_data )
       SELECT trim(Substr(mod_str, start_pos, end_pos-start_pos)) str
       FROM (
             SELECT *
             FROM   model_param
             MODEL PARTITION BY ( rn, orig_str, mod_str)
             DIMENSION BY (element_no)
             MEASURES (start_pos, end_pos, element_count)
             RULES ITERATE (2000)
             UNTIL (ITERATION_NUMBER+1 = element_count[0])
           ( start_pos[ITERATION_NUMBER+1] =
                     instr(cv(mod_str), ',', 1, cv(element_no)) + 1,
             end_pos[ITERATION_NUMBER+1] =
                     instr(cv(mod_str), ',', 1, cv(element_no) + 1) )
           )
        WHERE    element_no != 0
   ORDER BY      mod_str ,
                 element_no
   /

<强>输出

STR
----------------------
12 3
456




abc
def

8 rows selected.

如果你想在 PL / SQL 中进行,那么你可以使用流水线表函数:

SQL> CREATE OR REPLACE TYPE test_type
  2  AS
  3    TABLE OF VARCHAR2(100)
  4  /

Type created.

SQL> CREATE OR REPLACE FUNCTION comma_to_table(
  2      p_list IN VARCHAR2)
  3    RETURN test_type PIPELINED
  4  AS
  5    l_string LONG := p_list || ',';
  6    l_comma_index PLS_INTEGER;
  7    l_index PLS_INTEGER := 1;
  8  BEGIN
  9    LOOP
 10      l_comma_index := INSTR(l_string, ',', l_index);
 11      EXIT
 12    WHEN l_comma_index = 0;
 13      PIPE ROW ( TRIM(SUBSTR(l_string, l_index, l_comma_index - l_index)));
 14      l_index := l_comma_index                                + 1;
 15    END LOOP;
 16  RETURN;
 17  END comma_to_table;
 18  /

Function created.

让我们看一下输出

SQL> SELECT *
  2  FROM TABLE(comma_to_table('12 3,456,,,,,abc,def'))
  3  /

COLUMN_VALUE
------------------------------------------------------------------------------
12 3
456




abc
def

8 rows selected.

SQL>