2015-02-23 33 views
12

İki parametreyi alacak olan Bölünme işlevine, dizeyi bölmek ve dizgeyi ayırmak için bölme ve ayırıcıya ayırmak için Bölme işlevi gerekir. Sütun Kimliği ve Verileri ile bir tablo döndürün. Kimlik sütunu sıralamayı içerecek ve veri sütunu dizenin verilerini içerecektir. Ör.Otomatik dizgisiyle virgülle ayrılmış değerler için bölme içinde bölünmüş işlev

SELECT*FROM Split('A,B,C,D',',') 

Sonucu formatında aşağıda olmalı:

İşte
|Id | Data 
-- ---- 
|1 | A | 
|2 | B | 
|3 | C | 
|4 | D | 
+2

Bkz. [** Tek virgülle ayrılmış dizeyi Oracle'daki satırlara ayırın] (https://lalitkumarb.com/2014/12/02/split-comma-delimited-string-into-rows-in-oracle/) –

+0

Bağlantının üstünde, lütfen [** Tek virgülle ayrılmış dizeyi Oracle'da satırlara ayırın] (https://lalitkumarb.wordpress.com/2014/12/02/split-comma-delimited-string-into- satır-in-oracle /) –

cevap

13

böyle bir tablo oluşturmak nasıl geçerli: birazcık ile

SELECT LEVEL AS id, REGEXP_SUBSTR('A,B,C,D', '[^,]+', 1, LEVEL) AS data 
    FROM dual 
CONNECT BY REGEXP_SUBSTR('A,B,C,D', '[^,]+', 1, LEVEL) IS NOT NULL; 

verdiği (yani , değiştirilmesi Bir değişken ile [^,] içinde) bir tablo döndürmek için böyle bir işlev yazabilirsiniz.

4

Bir işleve ihtiyacınız varsa bunu deneyin.

CREATE OR REPLACE FUNCTION TEST_RETURN_TABLE 
RETURN T_TABLE_COLL 
    IS 
     l_res_coll T_TABLE_COLL; 
     l_index number; 
    BEGIN 
     l_res_coll := T_TABLE_COLL(); 
     FOR i IN (
     WITH TAB AS 
      (SELECT '1001' ID, 'A,B,C,D,E,F' STR FROM DUAL 
      UNION 
      SELECT '1002' ID, 'D,E,F' STR FROM DUAL 
      UNION 
      SELECT '1003' ID, 'C,E,G' STR FROM DUAL 
     ) 
     SELECT id, 
      SUBSTR(STR, instr(STR, ',', 1, lvl) + 1, instr(STR, ',', 1, lvl + 1) - instr(STR, ',', 1, lvl) - 1) name 
     FROM 
      (SELECT ',' || STR || ',' AS STR, id FROM TAB 
     ), 
      (SELECT level AS lvl FROM dual CONNECT BY level <= 100 
     ) 
     WHERE lvl <= LENGTH(STR) - LENGTH(REPLACE(STR, ',')) - 1 
     ORDER BY ID, NAME) 
     LOOP 
     IF i.ID = 1001 THEN 
      l_res_coll.extend; 
      l_index := l_res_coll.count; 
      l_res_coll(l_index):= T_TABLE(i.ID, i.name); 
     END IF; 
     END LOOP; 
     RETURN l_res_coll; 
    END; 
    /

Şimdi ondan seçebilirsiniz::

select * from table(TEST_RETURN_TABLE()); 

Çıktı:

CREATE OR REPLACE TYPE T_TABLE IS OBJECT 
(
    Field1 int 
    , Field2 VARCHAR(25) 
); 
CREATE TYPE T_TABLE_COLL IS TABLE OF T_TABLE; 
/

Sonra fonksiyonu yaratacağız:
Önce bir alanı oluşturacağız

SQL> select * from table(TEST_RETURN_TABLE()); 

    FIELD1 FIELD2 
---------- ------------------------- 
     1001 A 
     1001 B 
     1001 C 
     1001 D 
     1001 E 
     1001 F 

6 rows selected. 

Açıkçası, gerçek verilerinizi nereden alacağınız ile WITH TAB AS... bit değiştirmeniz gerekiyor. CreditCredit

+0

ve her ikisi de tür ve işlev derleme hatası gösteriliyor –

10

Birden çok seçenek vardır. Sadece döndü her satır için dizisi numarası almak için, bir sütun olarak seçme listesinde LEVEL eklemem gerekiyor Split single comma delimited string into rows in Oracle

bakınız. Veya, ROWNUM da yeterli olacaktır.

Aşağıdaki SQL'lerden herhangi birini kullanarak bunları bir FUNCTION'a ekleyebilirsiniz.

madde İLE InStrCONNECT içinde:İLE CONNECT içinde

 
SQL> WITH DATA AS 
    2 (SELECT 'word1, word2, word3, word4, word5, word6' str FROM dual 
    3 ) 
    4 SELECT trim(regexp_substr(str, '[^,]+', 1, LEVEL)) str 
    5 FROM DATA 
    6 CONNECT BY regexp_substr(str , '[^,]+', 1, LEVEL) IS NOT NULL 
    7/

STR 
---------------------------------------- 
word1 
word2 
word3 
word4 
word5 
word6 

6 rows selected. 

SQL> 

REGEXP_COUNT: madde İLE

 
SQL> WITH DATA AS 
    2 (SELECT 'word1, word2, word3, word4, word5, word6' str FROM dual 
    3 ) 
    4 SELECT trim(regexp_substr(str, '[^,]+', 1, LEVEL)) str 
    5 FROM DATA 
    6 CONNECT BY instr(str, ',', 1, LEVEL - 1) > 0 
    7/

STR 
---------------------------------------- 
word1 
word2 
word3 
word4 
word5 
word6 

6 rows selected. 

SQL> 

REGEXP_SUBSTRCONNECT içindefıkra:

 
SQL> WITH DATA AS 
    2  (SELECT 'word1, word2, word3, word4, word5, word6' str FROM dual 
    3  ) 
    4  SELECT trim(regexp_substr(str, '[^,]+', 1, LEVEL)) str 
    5  FROM DATA 
    6  CONNECT BY LEVEL 

kullanma MODEL maddesini kullanarak XMLTABLE

 
SQL> WITH DATA AS 
    2 (SELECT 'word1, word2, word3, word4, word5, word6' str FROM dual 
    3 ) 
    4 SELECT trim(COLUMN_VALUE) str 
    5 FROM DATA, xmltable(('"' || REPLACE(str, ',', '","') || '"')) 
    6/
STR 
------------------------------------------------------------------------ 
word1 
word2 
word3 
word4 
word5 
word6 

6 rows selected. 

SQL> 

:

 
SQL> WITH t AS 
    2 (
    3   SELECT 'word1, word2, word3, word4, word5, word6' str 
    4   FROM dual) , 
    5 model_param AS 
    6 (
    7   SELECT str AS orig_str , 
    8    ',' 
    9      || str 
10      || ','         AS mod_str , 
11    1            AS start_pos , 
12    Length(str)         AS end_pos , 
13    (Length(str) - Length(Replace(str, ','))) + 1 AS element_count , 
14    0            AS element_no , 
15    ROWNUM          AS rn 
16   FROM t) 
17 SELECT trim(Substr(mod_str, start_pos, end_pos-start_pos)) str 
18 FROM  (
19     SELECT * 
20     FROM model_param MODEL PARTITION BY (rn, orig_str, mod_str) 
21     DIMENSION BY (element_no) 
22     MEASURES (start_pos, end_pos, element_count) 
23     RULES ITERATE (2000) 
24     UNTIL (ITERATION_NUMBER+1 = element_count[0]) 
25     (start_pos[ITERATION_NUMBER+1] = instr(cv(mod_str), ',', 1, cv(element_no)) + 1, 
26     end_pos[iteration_number+1] = instr(cv(mod_str), ',', 1, cv(element_no) + 1))) 
27 WHERE element_no != 0 
28 ORDER BY mod_str , 
29   element_no 
30/

STR 
------------------------------------------ 
word1 
word2 
word3 
word4 
word5 
word6 

6 rows selected. 

SQL> 

Ayrıca kullanabilirsiniz DBMS_UTILITY Oracle tarafından sağlanan paketi. Çeşitli faydalı alt programlar sağlar. Böyle yararlı bir yardımcı program, adların virgülle ayrılmış bir listesini bir PL/SQL ad tablosuna dönüştüren COMMA_TO_TABLE yordamı'dur.

Oku DBMS_UTILITY.COMMA_TO_TABLE

5

Oracle Kurulumu:

CREATE OR REPLACE FUNCTION split_String(
    i_str IN VARCHAR2, 
    i_delim IN VARCHAR2 DEFAULT ',' 
) RETURN SYS.ODCIVARCHAR2LIST DETERMINISTIC 
AS 
    p_result  SYS.ODCIVARCHAR2LIST := SYS.ODCIVARCHAR2LIST(); 
    p_start  NUMBER(5) := 1; 
    p_end   NUMBER(5); 
    c_len CONSTANT NUMBER(5) := LENGTH(i_str); 
    c_ld CONSTANT NUMBER(5) := LENGTH(i_delim); 
BEGIN 
    IF c_len > 0 THEN 
    p_end := INSTR(i_str, i_delim, p_start); 
    WHILE p_end > 0 LOOP 
     p_result.EXTEND; 
     p_result(p_result.COUNT) := SUBSTR(i_str, p_start, p_end - p_start); 
     p_start := p_end + c_ld; 
     p_end := INSTR(i_str, i_delim, p_start); 
    END LOOP; 
    IF p_start <= c_len + 1 THEN 
     p_result.EXTEND; 
     p_result(p_result.COUNT) := SUBSTR(i_str, p_start, c_len - p_start + 1); 
    END IF; 
    END IF; 
    RETURN p_result; 
END; 
/

Sorgu

SELECT ROWNUM AS ID, 
     COLUMN_VALUE AS Data 
FROM TABLE(split_String('A,B,C,D')); 

Çıktı:

ID DATA 
-- ---- 
1 A 
2 B 
3 C 
4 D 
-3

altına

select 
    split.field(column_name,1,',','"') name1, 
    split.field(column_name,2,',','"') name2 
from table_name 
+0

Bu, Oracle, Sql Server değil. Etiketlere bakın. –

1

Kullanım gibi bu 'Bölünmüş' fonksiyonunu deneyin: Eğer soruda açıklandığı gibi

CREATE OR REPLACE FUNCTION Split (p_str varchar2) return sys_refcursor is 
v_res sys_refcursor; 

begin 
    open v_res for 
    WITH TAB AS 
    (SELECT p_str STR FROM DUAL) 
    select substr(STR, instr(STR, ',', 1, lvl) + 1, instr(STR, ',', 1, lvl + 1) - instr(STR, ',', 1, lvl) - 1) name 
    from 
    (select ',' || STR || ',' as STR from TAB), 
    (select level as lvl from dual connect by level <= 100) 
    where lvl <= length(STR) - length(replace(STR, ',')) - 1; 

    return v_res; 
    end; 

Sen select deyiminde bu işlevi kullanamazsınız, ancak Edeceğini umut Onu hala kullanışlı bul.

DÜZENLEME: İşte yapmanız gereken adımlar. 1. Nesne oluşturma: oluşturmak veya nesne olarak tip empy_type değiştirin (değer varchar2 (512)) 2. Tipi oluşturun: oluşturmak veya empy_type 3. tablosunda oluşturun Fonksiyon olarak tip t_empty_type değiştirin: sadece Ardından

CREATE OR REPLACE FUNCTION Split (p_str varchar2) return sms.t_empty_type is 
v_emptype t_empty_type := t_empty_type(); 
v_cnt  number := 0; 
v_res sys_refcursor; 
v_value nvarchar2(128); 
begin 
    open v_res for 
    WITH TAB AS 
    (SELECT p_str STR FROM DUAL) 
    select substr(STR, instr(STR, ',', 1, lvl) + 1, instr(STR, ',', 1, lvl +  1) - instr(STR, ',', 1, lvl) - 1) name 
    from 
    (select ',' || STR || ',' as STR from TAB), 
    (select level as lvl from dual connect by level <= 100) 
    where lvl <= length(STR) - length(replace(STR, ',')) - 1; 


    loop 
    fetch v_res into v_value; 
     exit when v_res%NOTFOUND; 
     v_emptype.extend; 
     v_cnt := v_cnt + 1; 
    v_emptype(v_cnt) := empty_type(v_value); 
    end loop; 
    close v_res; 

    return v_emptype; 
end; 

Bu gibi çağrı:

SELECT * FROM (TABLE(split('a,b,c,d,g'))) 
0

Bu işlev, MYSTRING giriş dizesinin nth bölümünü döndürür. İkinci giriş parametresi, örn.SEPARATOR_OF_SUBSTR ve üçüncü parametre gerekli olan Nth Part'dir.

Not: MYSTRING, ayırıcı ile bitmelidir.

create or replace FUNCTION PK_GET_NTH_PART(MYSTRING VARCHAR2,SEPARATOR_OF_SUBSTR VARCHAR2,NTH_PART NUMBER) 
RETURN VARCHAR2 
IS 
NTH_SUBSTR VARCHAR2(500); 
POS1 NUMBER(4); 
POS2 NUMBER(4); 
BEGIN 
IF NTH_PART=1 THEN 
SELECT REGEXP_INSTR(MYSTRING,SEPARATOR_OF_SUBSTR, 1, 1) INTO POS1 FROM DUAL; 
SELECT SUBSTR(MYSTRING,0,POS1-1) INTO NTH_SUBSTR FROM DUAL; 
ELSE 
SELECT REGEXP_INSTR(MYSTRING,SEPARATOR_OF_SUBSTR, 1, NTH_PART-1) INTO POS1 FROM DUAL; 
SELECT REGEXP_INSTR(MYSTRING,SEPARATOR_OF_SUBSTR, 1, NTH_PART) INTO POS2 FROM DUAL; 
SELECT SUBSTR(MYSTRING,POS1+1,(POS2-POS1-1)) INTO NTH_SUBSTR FROM DUAL; 
END IF; 
RETURN NTH_SUBSTR; 
END; 

Umut bu, bazı vücut, sen ayrılmış tüm değerleri almak için bir döngü içinde böyle bu işlevi kullanabilirsiniz yardımcı olur:

SELECT REGEXP_COUNT(MYSTRING, '~', 1, 'i') INTO NO_OF_RECORDS FROM DUAL; 
WHILE NO_OF_RECORDS>0 
LOOP 
    PK_RECORD :=PK_GET_NTH_PART(MYSTRING,'~',NO_OF_RECORDS); 
    -- do some thing 
    NO_OF_RECORDS :=NO_OF_RECORDS-1; 
END LOOP; 

İşte NO_OF_RECORDS, PK_RECORD geçici değişkenlerdir.

Bu yardımcı olur umarım.

İlgili konular