将逗号分隔为Oracle中的列

我有值返回255逗号分隔值。 有没有一个简单的方法来将它们分成没有255个substr的列?

ROW | VAL ----------- 1 | 1.25, 3.87, 2, ... 2 | 5, 4, 3.3, .... 

 ROW | VAL | VAL | VAL ... --------------------- 1 |1.25 |3.87 | 2 ... 2 | 5 | 4 | 3.3 ... 

你可以使用regexp_substr()

 select regexp_substr(val, '[^,]+', 1, 1) as val1, regexp_substr(val, '[^,]+', 1, 2) as val2, regexp_substr(val, '[^,]+', 1, 3) as val3, . . . 

我build议您在Excel(或其他电子表格)中生成255个数字的列,然后使用电子表格生成SQL代码。

谨防! 格式'[^,]+'的regexp_substrexpression式不会返回期望的值,如果在列表中有一个空元素,并且您希望该项目或之后的项目。 考虑这个例子,其中第四个元素是NULL,我想第五个元素,因此期望返回“5”:

 SQL> select regexp_substr('1,2,3,,5,6', '[^,]+', 1, 5) from dual; R - 6 

惊喜! 它返回第5个非NULL元素,而不是实际的第5个元素! 不正确的数据返回,你甚至可能没有抓住它。 试试这个:

 SQL> select regexp_substr('1,2,3,,5,6', '(.*?)(,|$)', 1, 5, NULL, 1) from dual; R - 5 

因此,上面更正的REGEXP_SUBSTR说要查找第五次出现的0个或更多的逗号分隔的字符,后跟一个逗号或行末(允许下一个分隔符,无论是逗号或行末)和当发现返回第一个小组(数据不包括逗号或行尾)。

search匹配模式'(.*?)(,|$)'解释:

 ( = Start a group . = match any character * = 0 or more matches of the preceding character ? = Match 0 or 1 occurrences of the preceding pattern ) = End the 1st group ( = Start a new group (also used for logical OR) , = comma | = OR $ = End of the line ) = End the 2nd group 

编辑:更多信息添加和简化了正则expression式。

看到这个post的更多信息和build议将其封装在一个函数中,以便于重复使用: REGEX从列表中select第n个值,允许空值这是我发现格式'[^,]+'有问题的post。 不幸的是,这是正则expression式格式,您最常看到的问题是如何parsing列表。 我不寒而栗,想到所有不正确的数据被'[^,]+'

如果你只有一行,并有时间来创build你的

  • 创build自己的内置cto_table 函数来分割任何分隔符的string ,然后你可以使用PIVOT + LISTAGG来做到这一点,如下所示:

 select * from ( select rownum r , collection.* from TABLE(cto_table(',','1.25, 3.87, 2, 19,, 1, 9, ')) collection ) PIVOT ( LISTAGG(column_value) within group (order by 1) as val for r in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) ) 

仅供参考:以下是如何创buildcto_table函数:

 CREATE OR REPLACE TYPE t_my_list AS TABLE OF VARCHAR2(100); CREATE OR REPLACE FUNCTION cto_table(p_sep in Varchar2, p_list IN VARCHAR2) RETURN t_my_list AS l_string VARCHAR2(32767) := p_list || p_sep; l_sep_index PLS_INTEGER; l_index PLS_INTEGER := 1; l_tab t_my_list := t_my_list(); BEGIN LOOP l_sep_index := INSTR(l_string, p_sep, l_index); EXIT WHEN l_sep_index = 0; l_tab.EXTEND; l_tab(l_tab.COUNT) := TRIM(SUBSTR(l_string,l_index,l_sep_index - l_index)); l_index := l_sep_index + 1; END LOOP; RETURN l_tab; END cto_table; /