The query you're trying to get to:
SELECT id, split_function(city) FROM COMMA_SEPERATED
won't work, because you're trying to return multiple rows for each source row. You have to make it a bit more complicated than that unfortunately.
If the goal is to hide the splitting mechanism then the closest I can think of is to create a function which returns a collection of strings, which could be pipelined:
create or replace function split_function (p_string varchar2)
return sys.odcivarchar2list pipelined as
begin
for r in (
select result
from xmltable (
'if (contains($X,",")) then ora:tokenize($X,"\,") else $X'
passing p_string as x
columns result varchar2(4000) path '.'
)
)
loop
pipe row (trim(r.result));
end loop;
end split_function;
/
Your proposed call would then give you one row per ID with a collection:
select id, split_function(city) from comma_seperated;
ID SPLIT_FUNCTION(CITY)
---------- -----------------------------------------------------------------
1 ODCIVARCHAR2LIST('CHENNAI', 'HYDERABAD', 'JABALPUR')
2 ODCIVARCHAR2LIST('BHOPAL', 'PUNE')
which isn't quite what you want; but you can use a table collection expression and cross-join to convert into multiple rows instead:
select cs.id, t.column_value as city
from comma_seperated cs
cross join table(split_function(cs.city)) t;
ID CITY
---------- ------------------------------
1 CHENNAI
1 HYDERABAD
1 JABALPUR
2 BHOPAL
2 PUNE
db<>fiddle demo.
That isn't as simple as you hoped for, but is arguably still better than cross-joining to the xmltable()
, particularly if you want to reuse that splitting logic/function in multiple places, as well as hide the details of how the split is done - which would let you change the mechanism easily if you wanted to, e.g. to use a more common regular expression to do the splitting.