I call a webservice and i get a list of codes: A, B, C, D, E, F etc.
In my problem i get A, B, C.
There\'s a table where you can create sets with the above codes
Oracle Setup:
Start with a simple function to split a delimited string into a collection:
CREATE OR REPLACE TYPE stringlist AS TABLE OF VARCHAR2(20)
/
CREATE OR REPLACE FUNCTION split_String(
i_str IN VARCHAR2,
i_delim IN VARCHAR2 DEFAULT ','
) RETURN stringlist DETERMINISTIC
AS
p_result stringlist := stringlist();
p_start NUMBER(5) := 1;
p_end NUMBER(5);
c_len CONSTANT NUMBER(5) := LENGTH( i_str );
c_ld CONSTANT NUMBER(5) := LENGTH( i_delim );
BEGIN
IF c_len > 0 THEN
p_end := INSTR( i_str, i_delim, p_start );
WHILE p_end > 0 LOOP
p_result.EXTEND;
p_result( p_result.COUNT ) := SUBSTR( i_str, p_start, p_end - p_start );
p_start := p_end + c_ld;
p_end := INSTR( i_str, i_delim, p_start );
END LOOP;
IF p_start <= c_len + 1 THEN
p_result.EXTEND;
p_result( p_result.COUNT ) := SUBSTR( i_str, p_start, c_len - p_start + 1 );
END IF;
END IF;
RETURN p_result;
END;
/
and some sample data:
CREATE TABLE your_table( setid, codes, messagedescr )
SELECT 1, 'A,B,C,D', 'You can login' FROM DUAL UNION ALL
SELECT 2, 'B,C,D', 'You can login for one day' FROM DUAL UNION ALL
SELECT 3, 'A,C,E', 'You can login but update your profile' FROM DUAL UNION ALL
SELECT 4, 'B,C,E,F', 'You cannot login' FROM DUAL;
Then you can do (passing your input C,A,B
- in any order - as the bind parameter :your_code
):
SELECT *
FROM (
SELECT *
FROM your_table
WHERE split_string( codes ) SUBMULTISET OF split_String( :your_code )
ORDER BY setid DESC
)
WHERE ROWNUM = 1;
and it will output the row with the highest matching set of codes.
Note: The above example assumes that you need to match all the codes in the table to codes in your input string. If you only need to match at least one then you can use:
WHERE split_string( codes ) MULTISET INTERSECT split_String( :your_code ) IS NOT EMPTY
If I understand well your need, this could be a way.
Say you have a table like this:
create table yourTable(setid, codes, messagedescr) as (
select 1, 'A, B, C, D', 'You can login' from dual union all
select 2, 'B, C, D' , 'You can login for one day' from dual union all
select 3, 'A, C, E' , 'You can login but update your profile' from dual union all
select 4, 'B, C, E, F', 'You cannot login' from dual
).
This could be a way:
with inputData(codes) as (
select listagg(trim (regexp_substr(input_codes, '[^,]+', 1, level))) within group ( order by trim (regexp_substr(input_codes, '[^,]+', 1, level)))
from ( select 'A, D, C, B' as input_codes from dual ) /* the input string */
CONNECT BY instr(input_codes, ',', 1, level - 1) > 0
)
select *
from inputData
inner join (
select listagg(trim (regexp_substr(codes, '[^,]+', 1, level)))
within group ( order by trim (regexp_substr(codes, '[^,]+', 1, level))) as codes,
messagedescr
from yourTable
CONNECT BY instr(codes, ',', 1, level - 1) > 0
and prior setId = setId
and prior sys_guid() is not null
group by setId, messagedescr
)
using (codes)
The idea here is to split your input string in many rows, and then aggregate the resulting rows in alphabetic order, then apply the same order on the values in table and then check that the ordered strings are equal.
This part is used to split, order and aggregate the input values, so that the result is an ordered string:
select listagg(trim (regexp_substr(input_codes, '[^,]+', 1, level))) within group ( order by trim (regexp_substr(input_codes, '[^,]+', 1, level)))
from ( select 'A, D, C, B' as input_codes from dual ) /* the input string */
CONNECT BY instr(input_codes, ',', 1, level - 1) > 0
gives:
ABCD
This part is used to do the same on your table:
select listagg(trim (regexp_substr(codes, '[^,]+', 1, level)))
within group ( order by trim (regexp_substr(codes, '[^,]+', 1, level))) as codes,
messagedescr
from yourTable
CONNECT BY instr(codes, ',', 1, level - 1) > 0
and prior setId = setId
and prior sys_guid() is not null
group by setId, messagedescr
gives:
CODES MESSAGEDESCR
---------- -------------------------------------
ABCD You can login
BCD You can login for one day
ACE You can login but update your profile
BCEF You cannot login
The join between these partial results is quite straightforward and simply checks if a value (ordered) exists in your table that corresponds to the (ordered) input string.