Home > Blockchain >  PLSQL Function to sort string that's given as parameter
PLSQL Function to sort string that's given as parameter

Time:03-17

following issue:

I get a String as such "512, 986, 571, 665" transferred as parameter, basically a set of 3 digit numbers and these need to be returned sorted from highest to lowest.

I have only found answers pertaining such an issue when the String is found in a table and not given as parameter to a function

CodePudding user response:

Here's one option: split input string into rows (that's what subquery in lines #4 - 6 does), and then aggregate them back using listagg with appropriate order by clause (line #3).

SQL> with test (col) as
  2    (select '512, 986, 571, 665' from dual)
  3  select listagg(val, ', ') within group (order by val) result
  4  from (select to_number(trim(regexp_substr(col, '[^,] ', 1, level))) val
  5        from test
  6        connect by level <= regexp_count(col, ',')   1
  7       );

RESULT
--------------------------------------------------------------------------------
512, 571, 665, 986

SQL>

CodePudding user response:

create or replace TYPE t_numlist IS table OF varchar2(32700);


create or replace function sort_num_string(p_strnum in varchar2) return varchar2 is
    l_numlist t_numlist:=t_numlist();
    v_nuber_count number;
    v_strbucket varchar2(32700):='';
    v_strnum varchar2(32700):=p_strnum;
    b_bool boolean:=true;
begin 
    v_nuber_count :=length(v_strnum)-length(replace(v_strnum,',','')) 1;
    l_numlist.extend(v_nuber_count);
    for i in 1..v_nuber_count loop
        l_numlist(i) := regexp_substr(v_strnum,'[0-9]{3}');
        v_strnum :=trim(substr(translate(v_strnum,',',' '),4));
    end loop;
    for i in (select * from table(l_numlist) order by 1)loop
        if b_bool then v_strbucket:=i.column_value;
                  else v_strbucket:=i.column_value||', '||v_strbucket;
        end if;
        b_bool:=false;
    end loop;
    
    RETURN v_strbucket;

exception
    when others then dbms_output.put_line('wrong entry');
end;

Test:

begin
    dbms_output.put_line(sort_num_string('234, 567, 908, 992, 723, 531, 555'));
end;

Result:

992, 908, 723, 567, 555, 531, 234


PL/SQL procedure successfully completed.

CodePudding user response:

One way would be to use the ability of xmltable to parse a comma-separated list into XML elements, then use its getclobval() method to convert each element into a string, then finally re-aggregate the strings using listagg:

create or replace function sort_number_list
    ( p_list varchar2 )
    return varchar2
as
    sorted_list varchar2(4000);
begin
    select listagg(x.column_value.getclobval(), ', ') within group (order by to_number(x.column_value.getclobval()))
    into   sorted_list
    from   xmltable(p_list) x;
    
    return sorted_list;
end sort_number_list;

Test:

select sort_number_list('97,3,-123,4')
from dual;

SORT_NUMBER_LIST('97,3,-123,4')
------------------------------------------------------------
-123, 3, 4, 97

CodePudding user response:

A programmatic approach would be to use each element in the list as the index of an associative array (so integers only, or it'll break), which will have the effect of sorting it, then loop through the resulting array constructing a new list:

create or replace function sort_number_list
    ( p_list varchar2 )
    return varchar2
as
    type aa is table of number index by pls_integer;
    sort_tab aa;
    sorted_list varchar2(4000);
begin
    for i in 1..regexp_count(p_list, ',')  1 loop
        sort_tab(trim(regexp_substr(p_list,'[^,] ', 1, i))) := i;
    end loop;

    for i in indices of sort_tab loop
        sorted_list := sorted_list || ', ' || i;
    end loop;

    return ltrim(sorted_list,', ');
end sort_number_list;

I've used the indices of syntax added in 21c which makes looping around an associative array less verbose.

  • Related