如何在oracle中将csv转换为表

如何创build一个以csv值forms传递结果的包。

select * from table(schema.mypackage.myfunction('one, two, three')) 

应该返回

 one two three 

我尝试了一些问题汤姆,但只适用于SQLtypes。

我正在使用oracle 11g。 有内置的东西吗?

下面的工作调用它作为select * from table(splitter('a,b,c,d'))

 create or replace function splitter(p_str in varchar2) return sys.odcivarchar2list is v_tab sys.odcivarchar2list:=new sys.odcivarchar2list(); begin with cte as (select level ind from dual connect by level <=regexp_count(p_str,',') +1 ) select regexp_substr(p_str,'[^,]+',1,ind) bulk collect into v_tab from cte; return v_tab; end; / 

唉,在11g中,我们仍然需要使用SQLtypes来手动编写我们自己的PL / SQL标记器。 在11gR2中,Oracle给了我们一个聚合函数来将结果连接成一个CSVstring,所以也许在12i中它们将提供反向能力。

如果你不想创build一个SQLtypes,特别是你可以使用内置的SYS.DBMS_DEBUG_VC2COLL,像这样:

 create or replace function string_tokenizer (p_string in varchar2 , p_separator in varchar2 := ',') return sys.dbms_debug_vc2coll is return_value SYS.DBMS_DEBUG_VC2COLL; pattern varchar2(250); begin pattern := '[^('''||p_separator||''')]+' ; select trim(regexp_substr (p_string, pattern, 1, level)) token bulk collect into return_value from dual where regexp_substr (p_string, pattern, 1, level) is not null connect by regexp_instr (p_string, pattern, 1, level) > 0; return return_value; end string_tokenizer; / 

这是在行动:

 SQL> select * from table (string_tokenizer('one, two, three')) 2 / COLUMN_VALUE ---------------------------------------------------------------- one two three SQL> 

致谢:这个代码是我在Tanel Poder的博客上find的一些代码的变体。

这里是另一个完全在sql中使用正则expression式匹配器的解决scheme。

 SELECT regexp_substr('one,two,three','[^,]+', 1, level) abc FROM dual CONNECT BY regexp_substr('one,two,three', '[^,]+', 1, level) IS NOT NULL 

为获得最佳性能,最好避免在分离器function中使用分层(CONNECT BY)查询。

当应用于更大的数据量时,下面的分离器函数可以更好地处理

 CREATE OR REPLACE FUNCTION row2col(p_clob_text IN VARCHAR2) RETURN sys.dbms_debug_vc2coll PIPELINED IS next_new_line_indx PLS_INTEGER; remaining_text VARCHAR2(20000); next_piece_for_piping VARCHAR2(20000); BEGIN remaining_text := p_clob_text; LOOP next_new_line_indx := instr(remaining_text, ','); next_piece_for_piping := CASE WHEN next_new_line_indx <> 0 THEN TRIM(SUBSTR(remaining_text, 1, next_new_line_indx-1)) ELSE TRIM(SUBSTR(remaining_text, 1)) END; remaining_text := SUBSTR(remaining_text, next_new_line_indx+1 ); PIPE ROW(next_piece_for_piping); EXIT WHEN next_new_line_indx = 0 OR remaining_text IS NULL; END LOOP; RETURN; END row2col; / 

这个性能差异可以在下面看到(我在前面的讨论中使用了function分离器)。

 SQL> SET TIMING ON SQL> SQL> WITH SRC AS ( 2 SELECT rownum||',a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z'||rownum txt 3 FROM DUAL 4 CONNECT BY LEVEL <=10000 5 ) 6 SELECT NULL 7 FROM SRC, TABLE(SYSTEM.row2col(txt)) t 8 HAVING MAX(t.column_value) > 'zzz' 9 ; no rows selected Elapsed: 00:00:00.93 SQL> SQL> WITH SRC AS ( 2 SELECT rownum||',a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z'||rownum txt 3 FROM DUAL 4 CONNECT BY LEVEL <=10000 5 ) 6 SELECT NULL 7 FROM SRC, TABLE(splitter(txt)) t 8 HAVING MAX(t.column_value) > 'zzz' 9 ; no rows selected Elapsed: 00:00:14.90 SQL> SQL> SET TIMING OFF SQL> 

我没有安装11g,但是有一个PIVOT和UNPIVOT操作,用于将列转换为行/列到列,这可能是一个很好的起点。

http://www.oracle.com/technology/pub/articles/oracle-database-11g-top-features/11g-pivot.html

(实际上已经做了一些进一步的调查,这不适合这种情况 – 它适用于实际的行/列,而不是一列中的数据集)。

还有DBMS_UTILITY.comma_to_table和table_to_comma用于将CSV列表转换为pl / sql表。 有一些限制(处理换行等),但可能是一个很好的起点。

我倾向于使用TYPE方法,用一个简单的函数comma_to_table,然后PIPE ROW为comma_to_table的结果中的每个条目(不幸的是,DBMS_UTILITY.comma_to_table是一个过程,所以不能从SQL调用)。