[oracle] Split function in oracle to comma separated values with automatic sequence

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 function which will return a table with columns Id and Data. Id column will contain sequence and data column will contain data of the string. Eg.

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

Result Should be in below format:

|Id | Data
 --   ----
|1  | A  |
|2  | B  |
|3  | C  |
|4  | D  |

This question is related to oracle function plsql split delimiter

The answer is


Best Query For comma separated in This Query we Convert Rows To Column ...

SELECT listagg(BL_PRODUCT_DESC, ', ') within
   group(   order by BL_PRODUCT_DESC) PROD
  FROM GET_PRODUCT
--  WHERE BL_PRODUCT_DESC LIKE ('%WASH%')
  WHERE Get_Product_Type_Id = 6000000000007

Try like below

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

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.


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'))) 

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.


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


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

If you need a function try this.
First we'll create a type:

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

Then we'll create the function:

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

Now we can select from it:

select * from table(TEST_RETURN_TABLE()); 

Output:

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

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

6 rows selected.

Obviously you'd need to replace the WITH TAB AS... bit with where you would be getting your actual data from. Credit Credit


Examples related to oracle

concat yesterdays date with a specific time ORA-28001: The password has expired how to modify the size of a column How to create a blank/empty column with SELECT query in oracle? Find the number of employees in each department - SQL Oracle Query to display all tablespaces in a database and datafiles When or Why to use a "SET DEFINE OFF" in Oracle Database How to insert date values into table error: ORA-65096: invalid common user or role name in oracle In Oracle SQL: How do you insert the current date + time into a table?

Examples related to function

$http.get(...).success is not a function Function to calculate R2 (R-squared) in R How to Call a Function inside a Render in React/Jsx How does Python return multiple values from a function? Default optional parameter in Swift function How to have multiple conditions for one if statement in python Uncaught TypeError: .indexOf is not a function Proper use of const for defining functions in JavaScript Run php function on button click includes() not working in all browsers

Examples related to plsql

How can you tell if a value is not numeric in Oracle? Why do I get PLS-00302: component must be declared when it exists? Split function in oracle to comma separated values with automatic sequence PLS-00428: an INTO clause is expected in this SELECT statement What is the max size of VARCHAR2 in PL/SQL and SQL? PLS-00201 - identifier must be declared Default Values to Stored Procedure in Oracle How to call Oracle MD5 hash function? Proper way of checking if row exists in table in PL/SQL block PLS-00103: Encountered the symbol when expecting one of the following:

Examples related to split

Parameter "stratify" from method "train_test_split" (scikit Learn) Pandas split DataFrame by column value How to split large text file in windows? Attribute Error: 'list' object has no attribute 'split' Split function in oracle to comma separated values with automatic sequence How would I get everything before a : in a string Python Split String by delimiter position using oracle SQL JavaScript split String with white space Split a String into an array in Swift? Split pandas dataframe in two if it has more than 10 rows

Examples related to delimiter

How do I hide the PHP explode delimiter from submitted form results? How do I use a delimiter with Scanner.useDelimiter in Java? Split function in oracle to comma separated values with automatic sequence Split String by delimiter position using oracle SQL SQL split values to multiple rows How to use delimiter for csv in python Hive load CSV with commas in quoted fields How to escape indicator characters (i.e. : or - ) in YAML Delimiters in MySQL Split comma separated column data into additional columns