0

I am looking for a function in Oracle like this

for example

select xxx('orange,apple,banana,strawberry,Blueberry,tomato', ',' 3) from dual;

THEN shows

orange,apple,banana,

It counts ',' to 3

and

select xxx('orange,apple,banana,strawberry,Blueberry,tomato', ',' ,2,3) from dual;

shows

banana,strawberry,Blueberry,

I hope this makes sense

Than you so much

SASPYTHON
  • 1,571
  • 3
  • 14
  • 30
  • What does the '2' in the second example represent? Should that call be starting from the second delimited value and getting the three values; or starting from the third and getting two? The result doesn't match either. – Alex Poole Aug 18 '17 at 17:39
  • sounds interesting. what have you tried so far? – tbone Aug 18 '17 at 17:45
  • @AlexPoole so orange '1',apple '2',banana '3',strawberry '4',Blueberry '5',tomato from "2," 2+3 = 5, to "5," therefore,"banana,strawberry,Blueberry," I hope this make senses for you. – SASPYTHON Aug 18 '17 at 17:52
  • So.. from *after* the second comma; and in the first query, implicitly after the 'zeroth' comma? – Alex Poole Aug 18 '17 at 17:54
  • yes, but this is just I made up, I could say like this.select xxx('orange,apple,banana,strawberry,Blueberry,tomato', ',' ,2,5) shows banana,strawberry,Blueberry – SASPYTHON Aug 18 '17 at 17:55

1 Answers1

2

There isn't a single built-in function that will do quite that. You could get close with regular expressions. But you could also create your own function to identify the starting and ending positions of the segment you want, based on the commas:

create function foo(p_str varchar2, p_delimiter varchar2,
  p_occurrences number, p_position number default 0)
return varchar2 is
  l_start pls_integer;
  l_end pls_integer;
  l_length pls_integer;
  l_result varchar2(4000);
begin
  l_start := case when p_position = 0 then 1
    else instr(p_str, p_delimiter, 1, p_position) + 1 end;
  l_end := instr(p_str, p_delimiter, l_start, p_occurrences);
  l_length := case when l_end = 0 then length(p_str) - l_start + 1
  else l_end - l_start end;

  l_result := substr(p_str, l_start, l_length);

  return l_result;
end;
/

Then, swapping around the arguments from your example, when you supply both (just to allow the default value for position to work like this):

select foo('orange,apple,banana,strawberry,Blueberry,tomato', ',', 1) from dual;

orange

select foo('orange,apple,banana,strawberry,Blueberry,tomato', ',', 3) from dual;

orange,apple,banana

select foo('orange,apple,banana,strawberry,Blueberry,tomato', ',', 3, 2) from dual;

banana,strawberry,Blueberry

select foo('orange,apple,banana,strawberry,Blueberry,tomato', ',', 3, 5) from dual;

tomato

If you ask for more occurrences than there are then it only returns as many as exist (i.e. just 'tomato' in the last call, despite asking for 3 elements). If your starting position is higher than the number of commas it returns the original string, but you can modify it to return null if you prefer.

You could do this in plain SQL with direct substr and instr calls but it gets a bit messy.

Another approach is to tokenise the original string (allowing for null elements), pick the tokens you want to keep, and stick them back together:

select listagg(token, ',') within group (order by position) as result
from (
  select level as position,
    regexp_substr('orange,apple,banana,strawberry,Blueberry,tomato',
      '(.*?)(,|$)', 1, level, null, 1) as token
  from dual
  connect by level <
    regexp_count('orange,apple,banana,strawberry,Blueberry,tomato', '(.*?)(,|$)')
)
where position between 3 and 5;

banana,strawberry,Blueberry
Alex Poole
  • 183,384
  • 11
  • 179
  • 318
  • Applause for not using the dangerous `'[^,]+'` regex which will not return the correct value when NULLs are present in the delimited list! – Gary_W Aug 18 '17 at 18:35
  • @Gary_W - I was trying to decide if I could squeeze a link to your post in, as I try to do whenever I use your approach ([as here](https://stackoverflow.com/a/45708598/266304); told you I'd bookmark it!); I've added it here now too. – Alex Poole Aug 18 '17 at 18:38
  • Thank you sir! I cringe when I think about the bad data getting returned out there and developers have no idea it's happening. – Gary_W Aug 18 '17 at 18:44
  • @AlexPoole Thank you so much!!! you have been helping me since yesterday – SASPYTHON Aug 18 '17 at 20:57