2013-07-16 4 views
6

मेरे पास पता फ़ील्ड है जिसमें 120 वर्ण हो सकते हैं और इसे तीन अलग-अलग स्तंभों में विभाजित करने की आवश्यकता है 40 charcaters प्रत्येक।तीन कॉलम में ओरेकल में वर्कर कॉलम को विभाजित करने के लिए

उदाहरण:

Table name: Address 
Column name: Street_Address 
Select Street_Address * from Address 

आउटपुट: 123 Main St North Pole Factory 44, near the rear entrance cross the street and turn left and keep walking straight.

मैं address_1 address_2 और address_3 में यह पता विभाजित करने के लिए की जरूरत है।

सभी तीन पते varchar(40) डेटाटाइप हैं।

तो परिणाम कुछ इस तरह होना चाहिए:

Address_1 
152 Main st North Pole Factory 44, near 

Address_2 
the rear entrance cross the street and 

Address_3 
turn left and keep walking straight. 

कृपया ध्यान दें कि प्रत्येक पता क्षेत्र 40 अक्षर तक का समय लग और पूरे शब्द हो गया है सकते हैं, यह छमाही में छोटा कर दिया नहीं किया जा सकता और अर्थहीन छोड़ दिया ।

मैं ऑरैकल 11i डेटाबेस का उपयोग कर रहा हूं।

+0

आप इन कॉलम कहां दिखाएंगे? आप इसे एप्लिकेशन स्तर पर क्यों विभाजित नहीं करते? – bjan

उत्तर

1

यह काफी "त्वरित और गंदे" है लेकिन मुझे लगता है कि यह सही परिणाम देता है।
मैं एक pipelined तालिका थे, लेकिन शायद यह इसके बिना किया जा सकता ...

Here is a sqlfiddle demo

create table t1(id number, adr varchar2(120)) 
/
insert into t1 values(1, '152 Main st North Pole Factory 44, near the rear entrance cross the street and turn left and keep walking straight.') 
/
insert into t1 values(2, '122 Main st Pole Factory 44, near the rear entrance cross the street and turn left and keep walking straight. asdsa') 
/

create or replace type t is object(id number, phrase1 varchar2(40), phrase2 varchar2(40), phrase3 varchar2(40)) 
/
create or replace type t_tab as table of t 
/

create or replace function split_string(id number, str in varchar2) return t_tab 
    pipelined is 

    v_token varchar2(40); 
    v_token_i number := 0; 
    v_cur_len number := 0; 
    v_res_str varchar2(121) := str || ' '; 
    v_p1  varchar2(40); 
    v_p2  varchar2(40); 
    v_p3  varchar2(40); 
    v_p_i  number := 1; 

begin 

    v_token_i := instr(v_res_str, ' '); 

    while v_token_i > 0 loop 

    v_token := substr(v_res_str, 1, v_token_i - 1); 

     if v_cur_len + length(v_token) < 40 then 

     if v_p_i = 1 then 
      v_p1 := v_p1 || ' ' || v_token; 
     elsif v_p_i = 2 then 
      v_p2 := v_p2 || ' ' || v_token; 
     elsif v_p_i = 3 then 
      v_p3 := v_p3 || ' ' || v_token; 
     end if; 

     v_cur_len := v_cur_len + length(v_token) +1; 
    else 
     v_p_i := v_p_i + 1; 

     if v_p_i = 2 then 
      v_p2 := v_p2 || ' ' || v_token; 
     elsif v_p_i = 3 then 
      v_p3 := v_p3 || ' ' || v_token; 
     end if; 

     v_cur_len := length(v_token); 

    end if; 

    v_res_str := substr(v_res_str, v_token_i + 1); 
    v_token_i := instr(v_res_str, ' '); 

    end loop; 

    pipe row(t(id, v_p1, v_p2, v_p3)); 
    return; 
end split_string; 
/

और क्वेरी:

select parts.*, length(PHRASE1), length(PHRASE2), length(PHRASE3) 
from t1, table(split_string(t1.id, t1.adr)) parts 
+0

@ डीएल, ओउप्स, आखिरी शब्द केस (जहां कोई जगह नहीं है) के बारे में भूल गया, मेरा जवाब अपडेट किया गया। (बीटीडब्लू, इसे ठीक करने का एक और तरीका है - आप 'v_res_str varchar2 (120): = str ||' ';' –

+0

@DL प्रारंभ कर सकते हैं, * फ्लाई * पर आपका क्या मतलब है? आप सुझाए गए प्रश्न का उपयोग कर सकते हैं दृश्य के रूप में (शायद लंबाई फ़ील्ड के बिना ...) –

+0

@ डी।एल, मुझे अभी भी समस्या नहीं दिखाई दे रही है - आप किसी अन्य कॉलम को भी जोड़ सकते हैं। इस उदाहरण को देखें http://www.sqlfiddle.com/#!4/eeb18/1 –

2

आप पुनरावर्ती सबक्वेरी फैक्टरिंग इस्तेमाल कर सकते हैं (पुनरावर्ती CTE):

with s (street_address, line, part_address, remaining) as (
    select street_address, 0 as line, 
    null as part_address, street_address as remaining 
    from address 
    union all 
    select street_address, line + 1 as line, 
    case when length(remaining) <= 40 then remaining else 
     substr(remaining, 1, instr(substr(remaining, 1, 40), ' ', -1, 1)) end 
     as part_address, 
    case when length(remaining) <= 40 then null else 
     substr(remaining, instr(substr(remaining, 1, 40), ' ', -1, 1) + 1) end 
     as remaining 
    from s 
) 
cycle remaining set is_cycle to 'Y' default 'N' 
select line, part_address 
from s 
where part_address is not null 
order by street_address, line; 

कौन सा बुद्धि एच आपका डेटा देता है:

 LINE PART_ADDRESS       
---------- ---------------------------------------- 
     1 152 Main st North Pole Factory 44, near 
     2 the rear entrance cross the street and 
     3 turn left and keep walking straight.  

SQL Fiddle demo दो पते के साथ।

आप उन आंशिक मानों को कॉलम में भी परिवर्तित कर सकते हैं, जो मुझे लगता है कि आपका अंतिम लक्ष्य है, उदा। एक दृश्य के रूप में:

create or replace view v_address as 
with cte (street_address, line, part_address, remaining) as (
    select street_address, 0 as line, 
    null as part_address, street_address as remaining 
    from address 
    union all 
    select street_address, line + 1 as line, 
    case when length(remaining) <= 40 then remaining else 
     substr(remaining, 1, instr(substr(remaining, 1, 40), ' ', -1, 1)) end 
     as part_address, 
    case when length(remaining) <= 40 then null else 
     substr(remaining, instr(substr(remaining, 1, 40), ' ', -1, 1) + 1) end 
     as remaining 
    from cte 
) 
cycle remaining set is_cycle to 'Y' default 'N' 
select street_address, 
    cast (max(case when line = 1 then part_address end) as varchar2(40)) 
    as address_1, 
    cast (max(case when line = 2 then part_address end) as varchar2(40)) 
    as address_2, 
    cast (max(case when line = 3 then part_address end) as varchar2(40)) 
    as address_3 
from cte 
where part_address is not null 
group by street_address; 

Another SQL Fiddle

यह ध्यान देने योग्य हो सकता है कि street_address लंबाई 120 वर्णों के करीब हो जाती है, तो यह 3 40-चार ब्लॉक में अच्छी तरह से फिट नहीं हो सकती है - आप अगले 'रेखा' में लिपटे शब्द की लंबाई के आधार पर कुछ वर्ण खो देते हैं । यह दृष्टिकोण 3 से अधिक लाइनों को उत्पन्न करेगा, लेकिन दृश्य केवल पहले तीन का उपयोग कर रहा है, ताकि आप पते का अंत खो सकें। आप फ़ील्ड को अधिक लंबा बनाना चाहते हैं, या address_4 उन स्थितियों के लिए ...

संबंधित मुद्दे