2010-10-23 12 views
21

में स्ट्रिंग अलग मैं सीएसवी स्ट्रिंग 100.01,200.02,300.03 जो मैं Oracle में एक PL/SQL संग्रहित प्रक्रिया को पास किए जाने है। proc के अंदर, मुझे इन मानों को तालिका में संख्या कॉलम में डालने की आवश्यकता है।विभाजन अल्पविराम एक PL/SQL संग्रहीत proc

इस के लिए, मैं यहाँ भर से एक काम दृष्टिकोण मिल गया:

How to best split csv strings in oracle 9i

[2) एसक्यूएल के स्तर से कनेक्ट का उपयोग करना।]।

अब, मैं एक और आवश्यकता है। मुझे पीएल/एसक्यूएल संग्रहीत प्रोसेस में इनपुट के रूप में 2 सीएसवी स्ट्रिंग्स [लंबाई में बराबर] पास करने की आवश्यकता है। और, मुझे इस स्ट्रिंग को तोड़ने और तालिका में दो अलग-अलग कॉलम में दो सीएसवी स्ट्रिंग्स से प्रत्येक मान डालना होगा। क्या आप कृपया मुझे पता है कि इसके बारे में कैसे जाना है? सीएसवी आदानों की

उदाहरण: 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 मूल्यों में जाना होगा।

तुम मुझे जानते हो कि यह कैसे प्राप्त करने के लिए कृपया सकता है?

धन्यवाद।

+0

देखें http://nuijten.blogspot.com/2009/07/splitting-comma-delimited-strin g-regexp.html - ओरेकल – InSane

उत्तर

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

+0

lname_array एक सारणी है: TYPE lname_array VARCHAR2 (4000) INDEX का BINARY_INTEGER द्वारा तालिका है; - तो आप इसे केवल –

+1

से चुन सकते हैं, लेकिन एक अच्छी शुरुआत है, लेकिन यहां कुछ और काम आवश्यक है: आप पैकेज में घोषित पीएल/एसक्यूएल सरणी प्रकार से 'चयन' नहीं कर सकते हैं। यदि आपने स्कीमा स्तर पर एक टेबल प्रकार घोषित किया है, तो आप इसे 'टैबलेट()' ऑपरेटर के साथ डालने पर इसका चयन कर सकते हैं। –

3

मुझे यकीन है कि अगर यह आपके Oracle संस्करण फिट बैठता है नहीं कर रहा हूँ। मेरी 10 ग्राम पर रहा pipelined तालिका कार्यों का उपयोग कर सकते हैं:

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

आपकी प्रतिक्रिया के लिए धन्यवाद। लेकिन, ओरेकल 9i का उपयोग कर रहा हूं जो apex_util का समर्थन नहीं करता है। – Jimmy

+0

यह ठीक है, आप किसी भी "टोकनेज़र" फ़ंक्शन का उपयोग कर सकते हैं जैसे कि मैंने पोस्ट किए गए लिंक में से एक या आपके प्रश्न में जुड़े संबंधित प्रश्न के स्वीकृत उत्तर में से एक। प्रत्येक स्ट्रिंग को टोकननाइज़ करने के लिए बस इसे एक बार कॉल करें। –

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

कई अच्छे समाधान पहले से ही उपलब्ध कराए गए हैं। हालांकि, अगर वह एक बहुत ही सरल अल्पविराम प्रारूपित प्रारूप या समान में प्रदान किया जाता है, और गति महत्वपूर्ण है, तो मेरे पास आपके पास TABLE फ़ंक्शन (पीएल/एसक्यूएल में) के साथ समाधान है। मैंने कुछ अन्य समाधानों की रैंडउन भी प्रदान की है।

कृपया Blog Entry on Parsing a CSV into multiple columns के बारे में अधिक देखते हैं।

+0

यदि नीचे मतदान होता है, तो मैं एक टिप्पणी की सराहना करता हूं। मैंने जो समाधान प्रदान किया वह व्यापक प्रदर्शन ट्यूनिंग और शोध का परिणाम था। अगर आपको लगता है कि कुछ गलत है या गलत तरीके से प्रस्तुत किया गया है, तो मुझे यह जानने का लाभ हो सकता है कि मतदान के कारण क्या हैं। – YoYo

+1

मैंने वोट कम नहीं किया, लेकिन शायद यह इसलिए था क्योंकि यह उत्तर एक लिंक पर भारी निर्भर करता है। –

-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 बदल देते हैं: आ bb सीसी dd ee एफएफ gg hh ii जे जे