sqloracle-databaseplsqloracle-apexoracle18c

Reset counter when it encounters a zero in the column


date customer orders desired result
31-Mar cus1 1 1
01-Apr cus1 1 2
02-Apr cus1 0 0
03-Apr cus1 0 0
04-Apr cus1 1 1
05-Apr cus1 1 2
06-Apr cus1 1 3
07-Apr cus1 1 4
08-Apr cus1 1 5
09-Apr cus1 1 6
01-Apr cus2 0 0
02-Apr cus2 0 0
03-Apr cus2 1 1
04-Apr cus2 1 2
05-Apr cus2 1 3
06-Apr cus2 0 0
07-Apr cus2 1 1

Here I have a table with dates , customers and their orders... i want a column to look like desired result in order to get my report functional. How can i do this using sql?

I have tried

row_number() over(partition by customer_id,desired_result order by work_date)

but that doesnot work,

what it does is this - current results

date customer orders desired result current results
31-Mar cus1 1 1 1
01-Apr cus1 1 2 2
02-Apr cus1 0 0 1
03-Apr cus1 0 0 2
04-Apr cus1 1 1 3
05-Apr cus1 1 2 4
06-Apr cus1 1 3 5
07-Apr cus1 1 4 6
08-Apr cus1 1 5 7
09-Apr cus1 1 6 8
01-Apr cus2 0 0 1
02-Apr cus2 0 0 2
03-Apr cus2 1 1 1
04-Apr cus2 1 2 2
05-Apr cus2 1 3 3
06-Apr cus2 0 0 3
07-Apr cus2 1 1 4

Solution

  • with data(dat,  customer, orders, desired_result) as (
        select to_date('31-03', 'DD-MM'), 'cus1', 1, 1 from dual union all
        select to_date('01-04', 'DD-MM'), 'cus1', 1, 2 from dual union all
        select to_date('02-04', 'DD-MM'), 'cus1', 0, 0 from dual union all
        select to_date('03-04', 'DD-MM'), 'cus1', 0, 0 from dual union all
        select to_date('04-04', 'DD-MM'), 'cus1', 1, 1 from dual union all
        select to_date('05-04', 'DD-MM'), 'cus1', 1, 2 from dual union all
        select to_date('06-04', 'DD-MM'), 'cus1', 1, 3 from dual union all
        select to_date('07-04', 'DD-MM'), 'cus1', 1, 4 from dual union all
        select to_date('08-04', 'DD-MM'), 'cus1', 1, 5 from dual union all
        select to_date('09-04', 'DD-MM'), 'cus1', 1, 6 from dual union all
        select to_date('01-04', 'DD-MM'), 'cus2', 0, 0 from dual union all
        select to_date('02-04', 'DD-MM'), 'cus2', 0, 0 from dual union all
        select to_date('03-04', 'DD-MM'), 'cus2', 1, 1 from dual union all
        select to_date('04-04', 'DD-MM'), 'cus2', 1, 2 from dual union all
        select to_date('05-04', 'DD-MM'), 'cus2', 1, 3 from dual union all
        select to_date('06-04', 'DD-MM'), 'cus2', 0, 0 from dual union all
        select to_date('07-04', 'DD-MM'), 'cus2', 1, 1 from dual -- union all
    )
    select d.dat, d.customer, d.orders,  
        case when orders <> 0 then row_number() over(partition by customer || 
            '-' || decode(orders,0,0,1) || '-' || cn  order by dat) else 0 end as rn
    from (
        select d.*,
            sum(case when orders = 0 then 1 else 0 end) over(partition by customer order by dat) as cn
        from data d
    ) d
    order by customer, dat
    ;
    
    31/03/24    cus1    1   1
    01/04/24    cus1    1   2
    02/04/24    cus1    0   0
    03/04/24    cus1    0   0
    04/04/24    cus1    1   1
    05/04/24    cus1    1   2
    06/04/24    cus1    1   3
    07/04/24    cus1    1   4
    08/04/24    cus1    1   5
    09/04/24    cus1    1   6
    01/04/24    cus2    0   0
    02/04/24    cus2    0   0
    03/04/24    cus2    1   1
    04/04/24    cus2    1   2
    05/04/24    cus2    1   3
    06/04/24    cus2    0   0
    07/04/24    cus2    1   1
    

    Or with MATCH_RECOGNIZE:

    SELECT dat,
           customer,
           orders,
           CASE  WHEN orders <> 0 THEN rn ELSE 0 END AS rn
    FROM   data
           MATCH_RECOGNIZE(
             PARTITION BY customer
             ORDER BY dat
             MEASURES
               COUNT(orders) AS rn
             ALL ROWS PER MATCH
             PATTERN ( WITH_ORDER+ | WITHOUT_ORDERS )
             DEFINE WITH_ORDER AS orders <> 0
           );