Split function in oracle to comma separated values with automatic sequence

后端 未结 8 946
遇见更好的自我
遇见更好的自我 2020-11-28 09:37

Need Split function which will take two parameters, string to split and delimiter to split the string and return a table with columns Id and Data.And how to call Split funct

相关标签:
8条回答
  • 2020-11-28 10:17

    Here is how you could create such a table:

     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;
    

    With a little bit of tweaking (i.e., replacing the , in [^,] with a variable) you could write such a function to return a table.

    0 讨论(0)
  • 2020-11-28 10:19

    This function returns the nth part of input string MYSTRING. Second input parameter is separator ie., SEPARATOR_OF_SUBSTR and the third parameter is Nth Part which is required.

    Note: MYSTRING should end with the separator.

    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;
    

    Hope this helps some body, you can use this function like this in a loop to get all the values separated:

    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;
    

    Here NO_OF_RECORDS,PK_RECORD are temp variables.

    Hope this helps.

    0 讨论(0)
  • 2020-11-28 10:21

    There are multiple options. See Split single comma delimited string into rows in Oracle

    You just need to add LEVEL in the select list as a column, to get the sequence number to each row returned. Or, ROWNUM would also suffice.

    Using any of the below SQLs, you could include them into a FUNCTION.

    INSTR in CONNECT BY clause:

    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_SUBSTR in CONNECT BY clause:

    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 in CONNECT BY clause:

    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 
    

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

    Using MODEL clause:

    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>
    

    You could also use DBMS_UTILITY package provided by Oracle. It provides various utility subprograms. One such useful utility is COMMA_TO_TABLE procedure, which converts a comma-delimited list of names into a PL/SQL table of names.

    Read DBMS_UTILITY.COMMA_TO_TABLE

    0 讨论(0)
  • 2020-11-28 10:36

    Use this 'Split' function:

    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;
    

    You can't use this function in select statement like you described in question, but I hope you will find it still useful.

    EDIT: Here are steps you need to do. 1. Create Object: create or replace type empy_type as object(value varchar2(512)) 2. Create Type: create or replace type t_empty_type as table of empy_type 3. Create Function:

    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;
    

    Then just call like this:

    SELECT * FROM (TABLE(split('a,b,c,d,g'))) 
    
    0 讨论(0)
  • 2020-11-28 10:40

    Try like below

    select 
        split.field(column_name,1,',','"') name1,
        split.field(column_name,2,',','"') name2
    from table_name
    
    0 讨论(0)
  • 2020-11-28 10:42

    Oracle Setup:

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

    Query

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

    Output:

    ID DATA
    -- ----
     1 A
     2 B
     3 C
     4 D
    
    0 讨论(0)
提交回复
热议问题