How to find the changed value in history table sql oracle

Viewed 147

I want to find out if the PAYMENT METHOD has been changed for a particular ID from the last time he pays.

ID PAYMENT METHOD DATE
1 CASH 2022
1 VISA 2021
1 CASH 2020
2 CASH 2021
2 CASH 2020
2 CASH 2019
3 CHEQUE 2021
3 VISA 2020
3 VISA 2019
4 CASH 2021
4 CASH 2020
4 CASH 2019

For example, ID 1 and ID 3 changed their payment method and I want to write a query that can detect that change, thanks in advance

example for expected outputs (I want to have a table that contains the changed payment method):

ID PAYMENT METHOD HAS CHANGED
1 CASH
3 CHEQUE
2 Answers

You just need simple aggregation with having clause: DBFiddle

select
   id, 
   max(payment_method)
     keep(dense_rank last order by dt) as LAST_PAYMENT_METHOD
from t
group by id
having count(distinct payment_method)>1;

Full example with test data:

with t(ID, PAYMENT_METHOD, DT) as (
select 1, 'CASH'  , to_date(2022,'YYYY') from dual union all
select 1, 'VISA'  , to_date(2021,'YYYY') from dual union all
select 1, 'CASH'  , to_date(2020,'YYYY') from dual union all
select 2, 'CASH'  , to_date(2021,'YYYY') from dual union all
select 2, 'CASH'  , to_date(2020,'YYYY') from dual union all
select 2, 'CASH'  , to_date(2019,'YYYY') from dual union all
select 3, 'CHEQUE', to_date(2021,'YYYY') from dual union all
select 3, 'VISA'  , to_date(2020,'YYYY') from dual union all
select 3, 'VISA'  , to_date(2019,'YYYY') from dual union all
select 4, 'CASH'  , to_date(2021,'YYYY') from dual union all
select 4, 'CASH'  , to_date(2020,'YYYY') from dual union all
select 4, 'CASH'  , to_date(2019,'YYYY') from dual
)
select
   id, 
   max(payment_method)
     keep(dense_rank last order by dt) as LAST_PAYMENT_METHOD
from t
group by id
having count(distinct payment_method)>1;

Output:

        ID LAST_PAYMENT_METHOD
---------- --------------------
         1 CASH
         3 CHEQUE

You can use the row_number() and count() analytic functions:

with u as
(select ID,
"PAYMENT METHOD",
row_number() over(partition by ID order by "DATE" desc) as rn,
count(distinct "PAYMENT METHOD") over(partition by ID) as cnt
from table_name)
select ID, "PAYMENT METHOD" from u
where rn = 1 and cnt >= 2
Related