In cases when you need to work with such delimited strings, it's often very convenient to use xml-functions, such as fn:string-join(), fn:tokenize().
For example:
xmltable(
'let $x:=tokenize($a,","), $y:=tokenize($b,",")
return fn:string-join($x[not(.=$y)],",")'
passing product as "a"
,prev_product as "b"
columns New_Products varchar(100) path '.'
) x
This xmltable() splits input parameters product and prev_product and returns those substrings from product that are not in prev_product:
- Function
tokenize($a, ",")
splits input string $a using comma as a delimiter.
$x[not(.=$y)]
returns those values from $x that do not exist in $y
- Function
string-join($arg1, ",")
concatenates values from $arg1 using comma as a delimiter.
Full example:
with
test (id, year_mth, product) as
-- your sample data (as well as some of my sample data)
(select 123, 201901, '1,2,3' from dual union all
select 123, 201902, '1,2,4,5' from dual union all
select 123, 201903, '2,3,4,6' from dual union all
select 123, 201904, '1,4,5,6' from dual union all
--
select 888, 201901, 'apple,banana' from dual union all
select 888, 201902, 'apple,banana' from dual union all
select 888, 201903, 'apple,lemon' from dual
)
select
t.*
,x.*
from
(
select
t.*
,lag(t.product)over(partition by id order by year_mth) prev_product
from test t
) t
,xmltable(
'let $x:=tokenize($a,","), $y:=tokenize($b,",")
return fn:string-join($x[not(.=$y)],",")'
passing product as "a"
,prev_product as "b"
columns New_Products varchar(100) path '.'
) x;
I made the xquery above so long just to make it more readable.
In real life xquery would be much shorter:
fn:string-join(tokenize($a,",")[not(.=tokenize($b,","))],",")
with
test (id, year_mth, product) as
-- your sample data (as well as some of my sample data)
(select 123, 201901, '1,2,3' from dual union all
select 123, 201902, '1,2,4,5' from dual union all
select 123, 201903, '2,3,4,6' from dual union all
select 123, 201904, '1,4,5,6' from dual union all
--
select 888, 201901, 'apple,banana' from dual union all
select 888, 201902, 'apple,banana' from dual union all
select 888, 201903, 'apple,lemon' from dual
)
select
t.*
,x.*
from
(
select
t.*
,lag(t.product)over(partition by id order by year_mth) prev_product
from test t
) t
,xmltable(
'fn:string-join(tokenize($a,",")[not(.=tokenize($b,","))],",")'
passing product as "a"
,prev_product as "b"
columns New_Products varchar(100) path '.'
) x