create or replace function get_token( the_list varchar2, the_index number, delim varchar2 := ',' ) return varchar2 is start_pos number; end_pos number; begin if the_index = 1 then start_pos := 1; else start_pos := instr(the_list, delim, 1, the_index - 1); if start_pos = 0 then return null; else start_pos := start_pos + length(delim); end if; end if; end_pos := instr(the_list, delim, start_pos, 1); if end_pos = 0 then return substr(the_list, start_pos); else return substr(the_list, start_pos, end_pos - start_pos); end if; end get_token; /Example usage:
select get_token('foo,bar,baz',1), -- 'foo' get_token('foo,bar,baz',3), -- 'baz' -- get_token('a,,b',2), -- '' (null) get_token('a,,b',3), -- 'b' -- get_token('a|b|c',2,'|'), -- 'b' get_token('a|b|c',4,'|') -- '' (null) from dual /Notes
- Remember that the index starts at one not zero just like strings in PL/SQL.
- Empty tokens are counted. You get null if you ask for an empty token.
- You also get null if you ask for an index greater than the number of tokens.
- The delimiter defaults to a comma but you can specify any delimiter. A delimiter of more than one char should work also.
Update 22/8/12
When I wrote this I didn't know about regexp_substr. (Or maybe the version of Oracle I was using didn't have it). You can do this much easier using the regexp_substr method. Have a look at the regexp_substr docs or see some examples in the comments below. For example:
regexp_substr('abc_def_ghi','[^_]+',1,3);
==> ghi.
Hey! Thanks for the SQL token function, it was just what I needed!
ReplyDeleteThis function rocks my socks. Thank you, stranger!
ReplyDeleteGreat ! ! !
ReplyDeleteNice and simple - just what I needed. Many thanks!
ReplyDeletepretty much the best tokenizer ever! thanks!
ReplyDeletethanks a lot. Very usefull !
ReplyDeleteVery GOOD!!!
ReplyDeletethank you mr. simon(i hope,... it's your name... )
ReplyDeleteGood work, friend! Helped me a lot :)
ReplyDeleteYeah Thanks
ReplyDeleteThank you so much! You are my new hero.
ReplyDeleteThank's a lot. I saved a lot of time. I've posted your solution on my blog and I've put a link pointing to your blog. Hope it's ok for you.
ReplyDeletehttp://fabrixb.blogspot.com/2007/07/oracle-plsql-function-to-split-strings.html
Thank you! It was just what i need!
ReplyDeleteYou saved my life :) Thank you very much.
ReplyDeleteAwesome! Thanks!
ReplyDeleteThank you so much, this rocks!
ReplyDeleteNot quite the same, but similar ... Oracle supplies a PL/SQL function to parse a[.b[.c]][@link] into a,b,c,link. It actually uses the Oracle parser to do the parsing.
ReplyDeletedbms_utility.name_tokenize()
Excellent function! Thanks for posting it.
ReplyDeleteI do never write comments. But this solution is something. Thank you a lot for saving a working day to me. Maybe more. I wouĞ´d give you a matrioska from Russia for this :-)
ReplyDeleteIn Spanish: Excelente función. Gracias por compartirla!!
ReplyDeletehey thanks a lot for this wonderful function ....really helped me a lot
ReplyDeleteHere is a version that uses regular expressions:
ReplyDeletecreate or replace function get_token(
the_list varchar2,
the_index number,
delim varchar2 := ','
)
return varchar2
is
begin
return regexp_substr(the_list, '[[:alnum:]]+', regexp_instr(the_list, delim, 1, the_index, 1));
end get_token;
hi! Thanks, exactly what I needed, had to modify it a bit to support multiple whitespaces, I posted a comment on my blog about it
ReplyDeletehttp://blog.thej2eestruggle.com/2008/01/removing-multiple-whitespace-from.html
thank you
ReplyDeletethis function has helped me much
Thank you
ReplyDeleteyour function help me
Pon007
The world's a better place when someone like you takes the time to write cool functions and then share them. Thanks!!
ReplyDeleteDear friend. You saved me a couple of days in writing and testing this. world is a beautiful place because of people who SHARE. Thanks friend. best wishes, Gopal.
ReplyDeletethx1.0e+6 4 this function
ReplyDeleteThanks, this script got me started. I found that I sometimes had quoted data with the delimiter inside such as (,"comma,inside",) and modified this to work for me.
ReplyDeleteHere it is:
function get_token(
the_list varchar2,
the_index number,
delim varchar2 := ',',
l_escape varchar2 := '"'
)
return varchar2
is
reg_exp varchar2(200);
result varchar2(3000);
begin
-- Comment exampls assume , delimiter and " escape
-- Search for ,text until , or text until comma from start of string
-- before variables are inserted (^|,)(".*"|[^,]*)'
reg_exp:= '(^|' || delim ||')(' || l_escape || '.*' || l_escape || '|[^' || delim || ']*)';
result:= regexp_substr(the_list, reg_exp , 1,the_index);
--remove any begining delimiters
reg_exp := '^' || delim;
result:= regexp_replace(result,reg_exp,'');
return result;
end get_token;
Worked great! Thanks for posting.
ReplyDeletegreat function
ReplyDeleteHey !! This function is excellent. Thanks for posting this.
ReplyDeleteThanks a lot for writing a generic tokenizer - I was looking for exactly this one! -Mukul
ReplyDeleteYou simply rule! Thank you so much
ReplyDeleteif you add feature of getting tokens from the end, the function will rock
ReplyDeleteexample : get_token ('a,b,c', -1) will return 'c'
yeah that would be cool.
ReplyDeleteI modified the function for the backend feature :
ReplyDeletecreate or replace
function get_token
(
the_list varchar2,
the_index number,
delim varchar2 :=';'
)
return varchar2
is
start_pos number;
end_pos number;
begin
if the_index = 1 then
start_pos := 1;
elsif the_index < 0 then
start_pos := instr(the_list, delim, -1, abs(the_index))+1;
else
start_pos := instr(the_list, delim, 1, the_index - 1);
if start_pos = 0 then
return null;
else
start_pos := start_pos + length(delim);
end if;
end if;
if the_index < 0 then
end_pos := instr(the_list, delim, start_pos+1, 1);
else
end_pos := instr(the_list, delim, start_pos, 1);
end if;
if end_pos = 0 then
return substr(the_list, start_pos);
else
return substr(the_list, start_pos, end_pos - start_pos);
end if;
end get_token;
Thanks man, exactly what I needed!
ReplyDeleteyou are the best!!!
ReplyDeleteu r a crack my man!!!
ReplyDeletecongratulations
Thank you a lot!
ReplyDeleteMil gracias!
Here is one that is recursive:
ReplyDelete/*
Recursive PL/SQL function that returns the nth element in a delimited String.
The default delimiter is a ',' (comma) and the level indicator defaults to 0.
*/
CREATE OR REPLACE FUNCTION getStringElement(p_string VARCHAR2,
p_element NUMBER,
p_delimiter VARCHAR2 := ',',
p_level NUMBER := 0) RETURN VARCHAR2
IS
v_string VARCHAR2(2000) := NULL;
v_element VARCHAR2(2000) := NULL;
v_level NUMBER(4) := 0;
BEGIN
v_level := p_level + 1;
v_element := substr(p_string||p_delimiter,1,instr(p_string||p_delimiter,p_delimiter)-1);
IF ((v_level >= p_element) OR (v_element IS NULL)) THEN
RETURN v_element;
ELSE
v_string := substr(p_string||p_delimiter,instr(p_string||p_delimiter,p_delimiter)+1,length(p_string));
RETURN getStringElement(v_string,p_element,p_delimiter,v_level);
END IF;
END;
/
Example:
The statement:
SELECT getStringElement('This is an interesting test of recursion in PL/SQL',7,' ') from dual;
will return the value "recursion".
http://radio.weblogs.com/0137094/2008/04/12.html
Its a great job. It helped me a lot and saved my lot of time.
ReplyDeleteGreat... Great... Great...
Hey thanks man,
ReplyDeleteYou have done a great job. It saved my time.
Very nice. Just used it in some code.
ReplyDeleteEthan Post
OK. Gonna use this for a SQL script for Geographic Information Project for dutch municipalities called BAG.
ReplyDeleteThanks.
ReplyDeleteI have added your code to my site.
http://www.coders2coders.com/articles.php?article_id=78
Thank you very much.
ReplyDeleteExactly what I needed.
You are great!!
ReplyDeleteReally useful, saved some time. Thanks!!
ReplyDeleteI just searched for the split function and urs was the first to get on Google...thanks buddy... and thanks google too..cheers!
ReplyDeletethank you very much for your code :D
ReplyDeletevery helpfull..
Very helpful - thanks! I am using it in my Data Warehouse ETL code.
ReplyDeletethank you so much!!!
ReplyDeleteif the_index =0 you will get an Error.
ReplyDelete:(
Anyone fixed that ???
For index = 0 just change first line to
ReplyDeleteif (the_index = 1 or the_index = 0) then
SAVED ME FROM LOOPING THROUGH A CURSOR & SUBSTR ing the text
ReplyDeleteThanks a lot!!!!
you`re so nice.
ReplyDeleteit`s help & inspire manythings for my final project of undergraduate..
i`ve been searching & trying few days to make this 'tokenizer' on pl-sql but always failed.
thanks for your help.
^_^
hi, great tip; you save a lot time for me.
ReplyDeletethk´s.
This is why I love internet :)
ReplyDeleteHere is my small contribution:
The get_token from Anonimus that supports index < 0 has a bug for delimiters longer then 1 and when U have a list that ends with delimiter.
So I fixed it and here it is:
create or replace function get_token (
p_red varchar2 := '111;222;333;444;',
p_index number :=1,
p_delimiter varchar2 :=';'
)
return varchar2
is
l_start number;
l_end number;
begin
if p_index = 1 then
l_start := 1;
elsif p_index < 0 then
if substr (p_red, -length(p_delimiter))= p_delimiter then
l_start := instr(p_red, p_delimiter, -1, abs(p_index)+1) + length(p_delimiter);
else
l_start := instr(p_red, p_delimiter, -1, abs(p_index))+ length(p_delimiter);
end if;
else
l_start := instr(p_red, p_delimiter, 1, p_index - 1) ;
if l_start = 0 then
return null;
else
l_start := l_start + length(p_delimiter);
end if;
end if;
if p_index < 0 then
l_end := instr(p_red, p_delimiter, l_start+1, 1);
else
l_end := instr(p_red, p_delimiter, l_start, 1);
end if;
if l_end = 0 then
return substr(p_red, l_start);
else
return substr(p_red, l_start, l_end - l_start);
end if;
end get_token;
Thanks for the function. I was looking for the same one. As I am not much familar to functions it really helped me a lot
ReplyDeleteThank you so much for posting the function.
ReplyDeleteI needed exactly the function that you wrote. Thanks to Google I found it and thanks to you I saved time (and CPU)!
ReplyDeleteThis might also be useful.
ReplyDeletehttp://www.oracle.com/technology/oramag/code/tips2007/070907.html
This might also be useful.
ReplyDeletehttp://www.oracle.com/technology/oramag/code
/tips2007
/070907.html
My earlier comment had a broken link.
In italian: Grazie per aver condiviso questa utile funzione
ReplyDeletesei il benvenuto
ReplyDeleteDear Sir,
ReplyDeleteI Can't Express My Feeling Toward Your Great Efforts...
You Have Done A Great Contribution To The Community...
Thank God
And I Thank You Very Much...
One God, The Creator, The Ruler.
All The Prophets From Adam Till Moses, Jesus And Mohamed Peace Be Upon All Of Them,
All Original Scripts
is My Belief....
You are the man!!!
ReplyDeleteYou saved the day! Thanks for the code. This is what I was looking for. Great job!
ReplyDeleteIs there something we can do to this function that can return array of values from the pipe seperated string? like
ReplyDeletefunction ('a|b|c|d', '|') may return
a
b
c
d
ok for the pl/sql solution, the "purist solution" would lead to : RETURN(a combination of simple predefined functions like "instr","substr","NVL")
ReplyDeletethis one made my life easy !!
ReplyDeleteMany thanks, quite possibly saved me a full workday!
ReplyDeleteTHX THX THX
ReplyDeleteThank you very much, just what I needed! Saved me some valuable time. Thanks for posting this useful snippet of code.
ReplyDeleteYou should also consider using regular expressions e.g. regexp_substr etc.
ReplyDeleteThat's awesome! What a travesty oracle does not have a "split" function.
ReplyDeleteyou are simply superb. great job done by you. excellent utilization of instr()
ReplyDeleteThank you so much, you're great!
ReplyDeleteFirst of all thanks for this blog. It helped me a lot.
ReplyDeleteI tried to use the regex solution as i have to split csv based fields, but it is not working.
It returns null for index >1 and returns entire string as it is for index = 1.
Please help!!!
Thanks a lot. Ur my life saver.
ReplyDeleteHi simon baird,
ReplyDeleteGreat Job. Thanks for your psot. your code really usful, ans I am using in project.
Thanks,
Kiran Nagaraju
Bangalore, India.
nkwm09@gmail.com
YOU ARE THE MAN!
ReplyDeletehi, i have something in this format (ck1=1/ar1=1,ar2=2,ar3=3)
ReplyDeletei have to split the string with delimiter "/" and then replace ck1 and ar* respectively.
Can you tell me how to do it using your funtion?
Thx so much, 5 years later this code saved me lots of time.
ReplyDeletegreat job
This function works good.
ReplyDeleteBut what i need is i have space(delimiter) more than one in a string, i want all the words exactly.
Example String:
'abc def ghi jkl'
i need
abc
def
ghi
jkl
please help me...
Thanks in advance......
Hi I have multiple spaces between words in the String. I want to separate the words exactly. please help me......
ReplyDeleteFor Examle:
'abc def ghi jkl mno'
same example with another delimiter:
'abc///def//ghi/jkl/////mno'
I need result as:
abc
def
ghi
jkl
mno
I am new to Oracle PL SQL. This function helped me out very much. Thank you very much.
ReplyDeleteKen
+1 (y)
ReplyDeleteAs much as reinventing the wheel can be cool, use this instead
ReplyDeleteregexp_substr('abc_def_ghi','[^_]+',1,3);
==> ghi.
David.
AWESOM MAN.. U REALLY ROCK!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! THXS 4 D CODE
ReplyDeleteNice work, saved me a TON of time!
ReplyDeleteReally awesome!
ReplyDeleteThanks a lot!
How to split the string 'ID=9999,DATE=27-AUG-2013,PROCESS_OPTION=100' ?
ReplyDeleteI need to get the values 999,27-AUG-2013,100 because these 2 values should need to pass as parameters to a procedure . The ID is a sequence number which will keep on increasing in every transaction.
Your help will be much appreciated.
superb code.It helped me to complete my task... nicely written.. thanks..
ReplyDeletesuperb code. It helped to complete my task.. nicely written.. thanks
ReplyDeletesuperb code. It helped to complete my task.. nicely written.. thanks
ReplyDeleteThis comment has been removed by a blog administrator.
ReplyDelete