Преобразовать строку с диапазонами числовых значений в строку отдельных чисел с запятой как разделителем

Допустим, есть символьная строка: 1-3,4,9,11-15.

Есть ли простой путь преобразовать её в строку отдельных чисел с запятой как разделителем в PL/SQL?

Можно найти множество решений, разбить строку по разделителю на отдельные значения, а также, собрать строку из отдельных значений. А как быть, если в строке встречаются диапазоны значений?

То есть, конечный результат хотелось бы видеть так: 1,2,3,4,9,11,12,13,14,15.


Свободный перевод вопроса Convert string with groups of numbers to a comma separated string with single numbers in PL/SQL от участника @Weltraumfahrer


Ответы (1 шт):

Автор решения: 0xdb

Взял за основу это решение (на db<>fiddle). Унаследовал с новым конструктором и одной вспомогательной функцией:

create or replace type TokenizerExt under Tokenizer (
    constructor function TokenizerExt (
        str varchar2, delimiter char:=',', spansign char:='-') return self as result,
    static function range (str varchar2, spansign char) return tokenList)
/
create or replace type body TokenizerExt as
    constructor function TokenizerExt (
        str varchar2, delimiter char:=',', spansign char:='-') return self as result is
        tmp tokenList := Tokenizer.split (str, delimiter);
    begin 
        self.tokens := tokenList (); --:= Tokenizer (str, delimiter).tokens; 
        for i in 1..tmp.count loop
            self.tokens := self.tokens multiset union TokenizerExt.range (tmp(i), spansign); 
        end loop;    
        return; 
    end;
    static function range (str varchar2, spansign char) return tokenList is
        ret tokenList := tokenList ();
        p int; 
    begin 
        if regexp_like (str, '^\d+'||spansign||'\d+$') then
            p := instr (str, spansign);
            for d in (substr (str, 1, p-1))..(substr (str, p+1)) loop
                ret.extend; ret(ret.last) := d; 
            end loop;
        else
           ret := tokenList (str);
        end if;
        return ret;
    end;
end;
/

Даст ожидаемый результат:

select TokenizerExt ('1-3,4,9,11-15').join() result from dual 
/

RESULT
------------------------------------------------------------
1,2,3,4,9,11,12,13,14,15
→ Ссылка