В SQL есть несколько способов разбить строки на строки. Мой предпочтительный метод - использовать рекурсивный подфакторный запрос (обычная табличная функция или CTE для толпы не оракула).
with city_group(grp, cities) as (
select 'group1', 'jammu##bhopal##chandigardh' from dual union all
select 'group2', 'Mumbai##kolkatta' from dual union all
select 'group3', 'bangalore' from dual
), Recur (grp, cities, city, nxt, lst) as (
-- Anchor Query
select grp, cities
, REGEXP_SUBSTR(cities,'(.+?)(##|$)',1,1,'',1)
, REGEXP_INSTR(cities,'(.+?)(##|$)',1,1,1)
, length(cities)
from city_group
-- Recursive part
union all
select grp, cities
, REGEXP_SUBSTR(cities,'(.+?)(##|$)',nxt,1,'',1)
, REGEXP_INSTR(cities,'(.+?)(##|$)',nxt,1,1)
, lst
from Recur
where nxt <= lst
)
select grp
, listagg(city,'##') within group (order by city)
from Recur
group by grp;
В приведенном выше коде якорный запрос возвращает первый элемент списка и устанавливает дополнительные столбцы для перебора списка значений. В частности, он возвращает следующие начальные позиции поиска (nxt
) и позицию последнего (lst
) символа в строке, используемой в качестве условия остановки для рекурсивной части.
Далее в рекурсивной части запроса последующие элементы списка возвращаются вместе с новой nxt
начальной позицией.
Использование движущейся стартовой позиции уменьшает объем работы, необходимой для поиска строки, когда вы продвигаетесь дальше в список значений.
Теперь слово об используемом регулярном выражении. Вместо ошибочной поисковой строки [^##]+
, которая функционально эквивалентна [^#]+
и которая может ошибочно идентифицировать одиночный #
в качестве разделителей строк, я использовал не жадную группу захвата (.+?)
, за которой следует группа захвата, которая явно соответствует маркер разделителя строк или символ конца строки (##|$)
. Затем функция REGEXP_SUBSTR
использует 6-й параметр, который указывает, что 1-я группа захвата содержит значение, которое должно быть возвращено, в то время как последний параметр функции REGEXP_INSTR
указывает, что позиция символа, следующая за соответствующей подстрокой, должна быть возвращена.
В качестве окончательного бонусного решения, если в вашей БД установлена последняя версия APEX, вы можете просто использовать табличную функцию APEX_STRING.split
следующим образом:
with city_group(grp, cities) as (
select 'group1', 'jammu##bhopal##chandigardh' from dual union all
select 'group2', 'Mumbai##kolkatta' from dual union all
select 'group3', 'bangalore' from dual
)
select grp
, listagg(column_value,'##') within group (order by column_value)
from city_group cg
cross apply apex_string.split(cities,'##')
group by grp;