Thursday, March 10, 2011

Splitting delimiter separated list into pl/sql table

I developed this code in 1999 when I used to code pl/sql for a living.
We used to have an order-entry system where the customer used to order multiple items and each item along with quantity used to sit as a row in the order detail table.
Our team wanted to avoid making multiple calls to the database for each order item.Therefore we told the UI folks to send us the customer "ordered" items as a single string list separated by a de-limiter and inside the procedure we would split the individual order items into a pl/sql table and then insert it into the order detail table.
I believe oracle has an in-built package to achieve the same in dbms_utility but I believe the below code is more robust in the sense that this could handle NULL values too.

For example if somebody passed  the following string (with * delimiter)

abc*xyz**mno

My procedure would break this up into

1.abc
2.xyz
3.NULL
4.mno

Likewise something like *abc**cvs* would be broken up as
1.NULL
2.abc
3.NULL
4.cvs
5.NULL

Here is the code to achieve the same.....



 CREATE OR REPLACE PACKAGE pk_genutilitypkg
  AS
     /*
     Generic String Parser: provide a delimiter and it returns an
     index-by table of the individual elements of the string that are
     separated by the specified delimiter.
     Author: "GAUTHAM CHANDRASEKARAN" <gautha@hotmail.com>
     */
    TYPE t_string IS TABLE OF VARCHAR2(2000)
       INDEX BY BINARY_INTEGER;
    m_ctr NUMBER(5);
    m_pos NUMBER(5);
    PROCEDURE sp_parsestring (
       p_string IN VARCHAR2,
       delimiter IN VARCHAR2,
       p_t_string OUT t_string);
END pk_genutilitypkg;
/

CREATE OR REPLACE PACKAGE BODY pk_genutilitypkg
 AS
    PROCEDURE sp_parsestring (
       p_string IN VARCHAR2,
       delimiter IN VARCHAR2,
       p_t_string OUT t_string)
    IS
       m_string VARCHAR2(4000);
    BEGIN
       /* Raise a Error if the length of the delimiter is not 1 */
       IF LENGTH (delimiter) != 1
       THEN
          raise_application_error (-20001,
              'Delimiter should be of only one character');
          RETURN;
       END IF;
       m_string := p_string;
       m_ctr := 1;
       LOOP
          m_pos := INSTR (m_string, delimiter);
          IF m_pos > 1
          THEN
             p_t_string (m_ctr) := SUBSTR (m_string, 1, m_pos - 1);
             IF (m_pos < LENGTH (m_string))
             THEN
                m_string := SUBSTR (
                               m_string,
                               m_pos + 1,
                               LENGTH (m_string) - m_pos
                            );
             ELSIF m_pos = LENGTH (m_string)
             THEN
                m_ctr := m_ctr + 1;
                p_t_string (m_ctr) := NULL;
                EXIT;
             END IF;
          ELSIF m_pos = 1
          THEN
             p_t_string (m_ctr) := NULL;
             IF m_pos < LENGTH (m_string)
             THEN
                m_string := SUBSTR (
                               m_string,
                               m_pos + 1,
                               LENGTH (m_string) - m_pos
                            );
             ELSIF m_pos = LENGTH (m_string)
             THEN
                m_ctr := m_ctr + 1;
                p_t_string (m_ctr) := NULL;
                EXIT;
             END IF;
          ELSIF m_pos = 0
          THEN
             p_t_string (m_ctr) := m_string;
             EXIT;
          END IF;
          m_ctr := m_ctr + 1;
       END LOOP;
    END;
END pk_genutilitypkg;
/


declare
x pk_genutilitypkg.t_string;
str1 varchar2(200):='121,234,345,657,890';
begin
pk_genutilitypkg.sp_parsestring(str1,',',x);

for i in 1..x.count
loop
dbms_output.put_line(x(i));

end loop;
end;
/






SQL> declare
  2  x pk_genutilitypkg.t_string;
  3  str1 varchar2(200):='121,234,345,657,890';
  4  begin
  5  pk_genutilitypkg.sp_parsestring(str1,',',x);
  6 
  7  for i in 1..x.count
  8  loop
  9  dbms_output.put_line(x(i));
 10 
 11  end loop;
 12  end;
 13  /

PL/SQL procedure successfully completed.

SQL> set serverout on
SQL> /
121
234
345
657
890

PL/SQL procedure successfully completed.

No comments:

Post a Comment