Senthadev

{ Think. Ask Why. Do it. }


Tokenizing column value to rows in SQL

While I was working on SQL query optimization, I came across the following sql “where” clause.

Let me explain the query first. Query was fetching all the developers who are connected to the provided project ID. And the end-user can invoke the query by providing a single project ID or list of project ID's which are separated by 'semicolon'.

For example,
Search value : “proj001;proj201;proj301;proj302”

(of couse this value is escaped before sending it to database (Oracle) to execute).

select *
from developers d
where (instr(';' || :SEARCH || ';', ';' || d.projectID || ';')) > 0;

-- And the :SEARCH will contain "proj001;proj201;proj301;proj302"

How could I tune this query?

Well, if I could convert the search value ( semicolon separated project ID's) into a virtual table of rows then I could perform a join statement and fetch all the records.

I could do it in two ways.


Tokenizing the string value using substr and instr functions.

select *
from developers d ,
   ( select 
        substr(search_text, 
            decode(level, 1, 1, instr(search_text, ';', 1, level-1) +1), 
            instr(search_text, ';', 1, level) - decode(level, 1, 1, instr(search_text, ';', 1, level-1) +1) ) proj_id
      from (select :SEARCH || ';' search_text from dual)
      connect by level <= length(search_text) - length(replace(search_text, ';'))) s
 where d.proj_id = s.proj_id;


Tokenizing the string using regEx.

select *
from developers d ,
   ( select 
        regexp_substr(search_text, '[^;]+', 1, level) proj_id
     from (select :SEARCH || ';' search_text from dual)
      connect by level <= length(search_text) - length(replace(search_text, ';'))) s
 where d.proj_id = s.proj_id;

2014-04-29
By @Senthadev