Splitting comma separated string in a PL/SQL stored proc

前端 未结 8 1795
别跟我提以往
别跟我提以往 2020-11-30 05:08

I\'ve CSV string 100.01,200.02,300.03 which I need to pass to a PL/SQL stored procedure in Oracle. Inside the proc,I need to insert these values in a Number column in the ta

相关标签:
8条回答
  • 2020-11-30 05:33

    As for the connect by use case, this approach should work for you:

    select regexp_substr('SMITH,ALLEN,WARD,JONES','[^,]+', 1, level)
    from dual
    connect by regexp_substr('SMITH,ALLEN,WARD,JONES', '[^,]+', 1, level) is not null;
    
    0 讨论(0)
  • 2020-11-30 05:36

    This should do what you are looking for.. It assumes your list will always be just numbers. If that is not the case, just change the references to DBMS_SQL.NUMBER_TABLE to a table type that works for all of your data:

    CREATE OR REPLACE PROCEDURE insert_from_lists(
        list1_in IN VARCHAR2,
        list2_in IN VARCHAR2,
        delimiter_in IN VARCHAR2 := ','
    )
    IS 
        v_tbl1 DBMS_SQL.NUMBER_TABLE;
        v_tbl2 DBMS_SQL.NUMBER_TABLE;
    
        FUNCTION list_to_tbl
        (
            list_in IN VARCHAR2
        )
        RETURN DBMS_SQL.NUMBER_TABLE
        IS
            v_retval DBMS_SQL.NUMBER_TABLE;
        BEGIN
    
            IF list_in is not null
            THEN
                /*
                || Use lengths loop through the list the correct amount of times,
                || and substr to get only the correct item for that row
                */
                FOR i in 1 .. length(list_in)-length(replace(list_in,delimiter_in,''))+1
                LOOP
                    /*
                    || Set the row = next item in the list
                    */
                    v_retval(i) := 
                            substr (
                                delimiter_in||list_in||delimiter_in,
                                instr(delimiter_in||list_in||delimiter_in, delimiter_in, 1, i  ) + 1,
                                instr (delimiter_in||list_in||delimiter_in, delimiter_in, 1, i+1) - instr (delimiter_in||list_in||delimiter_in, delimiter_in, 1, i) -1
                            );
                END LOOP;
            END IF;
    
            RETURN v_retval;
    
        END list_to_tbl;
    BEGIN 
       -- Put lists into collections
       v_tbl1 := list_to_tbl(list1_in);
       v_tbl2 := list_to_tbl(list2_in);
    
       IF v_tbl1.COUNT <> v_tbl2.COUNT
       THEN
          raise_application_error(num => -20001, msg => 'Length of lists do not match');
       END IF;
    
       -- Bulk insert from collections
       FORALL i IN INDICES OF v_tbl1
          insert into tmp (a, b)
          values (v_tbl1(i), v_tbl2(i));
    
    END insert_from_lists; 
    
    0 讨论(0)
  • 2020-11-30 05:39

    I use apex_util.string_to_table to parse strings, but you can use a different parser if you wish. Then you can insert the data as in this example:

    declare
      myString varchar2(2000) :='0.75, 0.64, 0.56, 0.45';
      myAmount varchar2(2000) :='0.25, 0.5, 0.65, 0.8';
      v_array1 apex_application_global.vc_arr2;
      v_array2 apex_application_global.vc_arr2;
    begin
    
      v_array1 := apex_util.string_to_table(myString, ', ');
      v_array2 := apex_util.string_to_table(myAmount, ', ');
    
      forall i in 1..v_array1.count
         insert into mytable (a, b) values (v_array1(i), v_array2(i));
    end;
    

    Apex_util is available from Oracle 10G onwards. Prior to this it was called htmldb_util and was not installed by default. If you can't use that you could use the string parser I wrote many years ago and posted here.

    0 讨论(0)
  • 2020-11-30 05:39

    Many good solutions have been provided already. However, if he text is provided in a very simple comma delimited format or similar, and speed is of importance, then I have for you a solution with a TABLE function (in PL/SQL). I have also provided a rundown of some other solutions.

    Please see more on the Blog Entry on Parsing a CSV into multiple columns.

    0 讨论(0)
  • 2020-11-30 05:42

    I am not sure if this fits your oracle version. On my 10g I can use pipelined table functions:

    set serveroutput on
    
    create type number_list as table of number;
    
    -- since you want this solution
    create or replace function split_csv (i_csv varchar2) return number_list pipelined 
      is 
        mystring varchar2(2000):= i_csv;
      begin
        for r in
        ( select regexp_substr(mystring,'[^,]+',1,level) element
            from dual
         connect by level <= length(regexp_replace(mystring,'[^,]+')) + 1
        )
        loop
          --dbms_output.put_line(r.element);
          pipe row(to_number(r.element, '999999.99'));
        end loop;
      end;
    /
    
    insert into foo
    select column_a,column_b from 
      (select column_value column_a, rownum rn from table(split_csv('0.75, 0.64, 0.56, 0.45'))) a 
     ,(select column_value column_b, rownum rn from table(split_csv('0.25, 0.5, 0.65, 0.8'))) b
     where a.rn = b.rn
    ;
    
    0 讨论(0)
  • 2020-11-30 05:44
    create or replace procedure pro_ss(v_str varchar2) as
    v_str1 varchar2(100); 
    v_comma_pos number := 0;    
    v_start_pos number := 1;
    begin             
        loop        
        v_comma_pos := instr(v_str,',',v_start_pos);   
        if  v_comma_pos = 0 then     
          v_str1 := substr(v_str,v_start_pos);  
          dbms_output.put_line(v_str1);    
          exit;
          end if;    
        v_str1 := substr(v_str,v_start_pos,(v_comma_pos - v_start_pos)); 
        dbms_output.put_line(v_str1);       
        v_start_pos := v_comma_pos + 1;    
        end loop; 
    end;
    /
    
    call pro_ss('aa,bb,cc,dd,ee,ff,gg,hh,ii,jj');
    

    outout: aa bb cc dd ee ff gg hh ii jj

    0 讨论(0)
提交回复
热议问题