2010-10-23 110 views
21

我已將CSV字符串100.01,200.02,300.03傳遞給Oracle中的PL/SQL存儲過程。 在proc中,我需要將這些值插入表中的Number列中。在PL/SQL存儲過程中分割逗號分隔的字符串

對於這一點,我從在這裏工作的方法:

How to best split csv strings in oracle 9i

[2)使用SQL的按級別進行連接。]。

現在,我有另一個要求。 我需要傳遞2個CSV字符串[長度相等]作爲PL/SQL存儲過程的輸入。而且,我需要打破此字符串,並將兩個CSV字符串中的每個值插入表中的兩個不同列。請允許讓我知道如何去做呢?

CSV輸入示例: mystring varchar2(2000):='0.75,0.64,0.56,0.45';

myAmount varchar2(2000):='0.25,0.5,0.65,0.8';

myString值將進入列A和myAmount值到表中的列B.

您能否讓我知道如何做到這一點?

謝謝。

+0

檢出http://nuijten.blogspot.com/2009/07/splitting-comma-delimited-strin g-regexp.html - 使用Oracle – InSane 2010-10-23 14:14:01

回答

7

這應該做你正在尋找..它假設你的列表將永遠只是數字。如果情況並非如此,只是改變DBMS_SQL.NUMBER_TABLE引用到的所有數據的工作表類型:

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; 
7

這裏是一個很好的解決方案:

FUNCTION comma_to_table(iv_raw IN VARCHAR2) RETURN dbms_utility.lname_array IS 
    ltab_lname dbms_utility.lname_array; 
    ln_len  BINARY_INTEGER; 
BEGIN 
    dbms_utility.comma_to_table(list => iv_raw 
           ,tablen => ln_len 
           ,tab => ltab_lname); 
    FOR i IN 1 .. ln_len LOOP 
     dbms_output.put_line('element ' || i || ' is ' || ltab_lname(i)); 
    END LOOP; 
    RETURN ltab_lname; 
END; 

來源: CSV - comma separated values - and PL/SQL (鏈接不再有效)

+0

中的正則表達式感謝您的評論,但是,該函數是否返回一個數組?如果是,那麼我將在proc中迭代它以在表中插入值。 – Jimmy 2010-10-23 14:51:28

+0

lname_array是一個表:TYPE lname_array IS TABLE OF VARCHAR2(4000)INDEX BY BINARY_INTEGER; - 所以你可以從中選擇 – 2010-10-23 19:31:36

+1

一個好的開始,但是這裏需要更多的工作:你不能在一個包中聲明一個PL/SQL數組類型。如果您在模式級別聲明瞭表類型,則可以從中選擇,如果使用TABLE()運算符進行轉換。 – 2010-10-24 13:39:06

3

我不知道這是否符合你的Oracle版本。在我10克我可以用流水錶功能:

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 
; 
6

我用apex_util.string_to_table解析字符串,但如果你願意,你可以使用不同的解析器。然後您可以插入數據,如下例所示:

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從Oracle 10G開始提供。在此之前,它被稱爲htmldb_util,默認情況下未安裝。如果你不能使用它,你可以使用我多年前寫的字符串解析器,併發布here

+0

感謝您的回覆。但是,我正在使用不支持apex_util的Oracle 9i。 – Jimmy 2010-10-27 13:52:26

+0

沒關係,你可以使用任何「tokenizer」函數,比如我發佈的鏈接中的那個,或者你的問題中鏈接到的相關問題的接受答案中的那個。只需爲每個要標記的字符串調用一次即可。 – 2010-10-27 14:16:18

3
CREATE OR REPLACE PROCEDURE insert_into (
    p_errcode  OUT NUMBER, 
    p_errmesg  OUT VARCHAR2, 
    p_rowsaffected OUT INTEGER 
) 
AS 
    v_param0 VARCHAR2 (30) := '0.25,2.25,33.689, abc, 99'; 
    v_param1 VARCHAR2 (30) := '2.65,66.32, abc-def, 21.5'; 
BEGIN 
    FOR i IN (SELECT COLUMN_VALUE 
       FROM TABLE (SPLIT (v_param0, ','))) 
    LOOP 
     INSERT INTO tempo 
        (col1 
       ) 
      VALUES (i.COLUMN_VALUE 
       ); 
    END LOOP; 

    FOR i IN (SELECT COLUMN_VALUE 
       FROM TABLE (SPLIT (v_param1, ','))) 
    LOOP 
     INSERT INTO tempo 
        (col2 
       ) 
      VALUES (i.COLUMN_VALUE 
       ); 
    END LOOP; 
END; 
-1

許多優秀的解決方案已經被提供。但是,如果他的文本以簡單逗號分隔的格式或類似的格式提供,並且速度很重要,那麼我需要爲您提供一個解決方案,使用PL/SQL中的函數TABLE。我還提供了一些其他解決方案的概要。

請參閱Blog Entry on Parsing a CSV into multiple columns的更多信息。

+0

如果發生投票,我將不勝感激。我提供的解決方案是廣泛的性能調整和研究的結果。如果您認爲某些事情是錯誤或歪曲的,我可以從中瞭解下調投票的原因。 – YoYo 2015-06-16 16:20:57

+1

我沒有投票,但可能是因爲這個答案很大程度上取決於一個鏈接。 – 2015-06-16 16:28:35

-1

對於connect by使用的情況下,這種做法應該爲你工作:

select regexp_substr('SMITH,ALLEN,WARD,JONES','[^,]+', 1, level) 
from dual 
connect by regexp_substr('SMITH,ALLEN,WARD,JONES', '[^,]+', 1, level) is not null; 
1

創建或替換procedure pro_ss(v_str varchar2)作爲

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

相關問題