Reputation: 223
I have a pl/sql nested table collection that contains the below elements:
AG~AG~1~14
US~BRANCH~1~24
NO~NO~2~10
KI~296~2~13
AI~AI~2~21
I have to look at the value in the 3rd subelement with each of these elements(not sure how to put it !) and pick the one that have the highest value. In the above data, the 3rd subelements are 1,1,2,2,2 (immediately following the second ~). Obviously here, the elements containing 2 are higher. So, 3 of them meet the criteria. Further, from the 3 of them, I have to look at the 4th subelement and ultimately pick the one that has the highest value. So, the 4th subelement for these 3 are: 10,13,21 Since 21 is the highest, the final output is to pick the element AI~AI~2~21.
I am struggling how to do this in the best possible way. I tried various combinations of instr and substr and looped them to compare. But, its not modular enough. I could also tokenize the string from each element and push into a global temp table that is valid for the session and then use oracle sql to get the final data. but, I want to avoid having to use a table and maintain it etc and if possible, like to keep it within pl/sql.
declare
TYPE final_score_typ IS TABLE OF varchar2(1000);
l_final_score final_score_typ;
l_final_output varchar2(20);
begin
<code logic that populates the nested table containing the above data>
for j in 1..l_final_score.count loop
dbms_output.put_line(l_final_score(j));
end loop;
dbms_output.put_line('final output string is:' || l_final_output);
end;
The final output should be printed as AI~AI~2~21 Any pointers would be much appreciated. I could atleast try based on them...Right now, cannot think of good alternatives.
Upvotes: 0
Views: 391
Reputation: 132570
There is an existing database type you can use for a table of VARCHAR2(1000): `
SYS.DBMS_DEBUG_VC2COLL
You could use it like this:
declare
l_data SYS.DBMS_DEBUG_VC2COLL := SYS.DBMS_DEBUG_VC2COLL
('AG~AG~1~14'
,'US~BRANCH~1~24'
,'NO~NO~2~10'
,'KI~296~2~13'
,'AI~AI~2~21'
);
l_result varchar2(100);
begin
select column_value
into l_result
from
( select column_value
, row_number() over
(order by substr(column_value
,instr(column_value,'~',1,2)+1
,instr(column_value,'~',1,3)
-instr(column_value,'~',1,2)-1
) desc
, substr(column_value,instr(column_value,'~',1,3)+1) desc
) as rn
from table (l_data)
) where rn = 1;
dbms_output.put_line(l_result);
end;
(Or you could use it with Egor's much more elegant regexp_substr code of course.)
Upvotes: 0
Reputation: 23737
select min(column_value) keep (dense_rank first order by
to_number(regexp_substr(column_value, '[^~]+', 1, 3)) desc,
to_number(regexp_substr(column_value, '[^~]+', 1, 4)) desc
)
into l_final_output
from table(l_final_score)
Note: type must be global:
create TYPE final_score_typ AS TABLE OF varchar2(1000);
Upvotes: 1