Создать функцию, превращающую одну CSV строку в таблицу, используя регулярное выражение для поиска разделителей
Подскажите пожалуйста как переделать следующий код:
with temp as
(
select 108 Name, 'test' Project, 'string-1 , string-2 ; string-3' Error from dual
union all
select 109, 'test2', 'single string' from dual
)
select distinct
t.name, t.project,
trim(regexp_substr(t.error, '[^,;]+', 1, levels.column_value)) as error
from
temp t,
table(cast(multiset(select level from dual connect by level <= length (regexp_replace(t.error, '[^,;]+')) + 1) as sys.OdciNumberList)) levels
order by name;
в универсальную функцию, которая принимает в качестве параметров строку (пример: 'string--1, string-2 ; string-3 , string-4') и регулярное выражение, задающее поиск разделителя строк (пример: '\s*[,;]\s*'):
FUNCTION csvstr2tab(
p_str IN VARCHAR2,
p_sep_re IN VARCHAR2 DEFAULT '\s*[,;]\s*'
)
...
В качестве собственных попыток - вот функция, которая выполняет данную задачу, используя фиксированный разделитель строк (','):
create or replace type admin.strtable as table of varchar2(1000);
/
create or replace
function admin.str2tbl ( p_str in varchar2 ) return strtable
as
l_str long default p_str || ',';
l_n number;
l_data strtable := strtable();
begin
loop
l_n := instr( l_str, ',' );
exit when (nvl(l_n,0) = 0);
l_data.extend;
l_data( l_data.count ) := ltrim(rtrim(substr(l_str,1,l_n-1)));
l_str := substr( l_str, l_n+1 );
end loop;
return l_data;
end;
/
PS sql<>fiddle
UPDATE: я использовал абревиатуру CSV только лишь для того, чтобы показать, что я имею дело со строками, в которых находяться подстроки, разделенные разделителями. На самом деле входные строки совсем не обязательно являются "валидными" CSV.
Ответы (1 шт):
Попробуйте воспроизводимый пример ниже (проверил на версии 12.2.0.1.0).
Подготовка схемы:
create table prjerr as
select 108 Name, 'test' Project, 'string-1 , string-2 ; string-3' Error from dual
union all
select 109, 'test2', 'single string' from dual
/
create or replace type tokenList is table of varchar2 (32767)
/
Сама функция:
create or replace function csvstr2tab (
str varchar2, delimiter char := '\s*[,;]\s*') return tokenList is
pattern constant varchar2 (64) := '(.*?)(('||delimiter||')|($))';
tokens tokenList := tokenList ();
s varchar2 (96);
c int := 0;
begin
<<split>> loop c := c + 1;
s := regexp_substr (str, pattern, 1, c, null, 1);
exit split when s is null;
tokens.extend;
tokens(tokens.last) := s;
end loop;
return tokens;
end csvstr2tab;
/
Запрос и результат:
select distinct name, project, t.column_value error
from prjerr p, csvstr2tab (p.error) t
order by name
/
NAME PROJE ERROR
---------- ----- ----------------
108 test string-1
108 test string-2
108 test string-3
109 test2 single string