Home > Mobile >  Need to number of Date increments in Oracle SQL
Need to number of Date increments in Oracle SQL

Time:05-20

Need the number of times the date is incremented in Oracle SQL

create table zzenp_so_multi_rs
(
so_number varchar2(30),
rev_number number,
line_number number, 
rs_date date,
status varchar2(30)
)
;

insert into zzenp_so_multi_rs (so_number,rev_number,line_number, rs_date, status ) values ('10000', 1, 1, '15-MAY-2022', 'Reference');
insert into zzenp_so_multi_rs (so_number,rev_number,line_number, rs_date, status ) values ('10000', 2, 1, '16-MAY-2022', 'Reference');
insert into zzenp_so_multi_rs (so_number,rev_number,line_number, rs_date, status ) values ('10000', 3, 1, '16-MAY-2022', 'Reference');
insert into zzenp_so_multi_rs (so_number,rev_number,line_number, rs_date, status ) values ('10000', 4, 1, '14-MAY-2022', 'Reference');
insert into zzenp_so_multi_rs (so_number,rev_number,line_number, rs_date, status ) values ('10000', 5, 1, '14-MAY-2022', 'Reference');
insert into zzenp_so_multi_rs (so_number,rev_number,line_number, rs_date, status ) values ('10000', 6, 1, '17-MAY-2022', 'Open');
insert into zzenp_so_multi_rs (so_number,rev_number,line_number, rs_date, status ) values ('10001', 1, 1, '17-MAY-2022', 'Reference');
insert into zzenp_so_multi_rs (so_number,rev_number,line_number, rs_date, status ) values ('10001', 2, 1, '15-MAY-2022', 'Reference');
insert into zzenp_so_multi_rs (so_number,rev_number,line_number, rs_date, status ) values ('10001', 3, 1, '12-MAY-2022', 'Reference');
insert into zzenp_so_multi_rs (so_number,rev_number,line_number, rs_date, status ) values ('10001', 4, 1, '16-MAY-2022', 'Reference');
insert into zzenp_so_multi_rs (so_number,rev_number,line_number, rs_date, status ) values ('10001', 5, 1, '13-MAY-2022', 'Open');

Here, we have Sales Order Number, Revision Number, Line Number, RS Date & Status. Each time a line is modified, another record is inserted and the status is modified to Reference for old record & Open for new record.

I need the calculation function / subquery for no_of_push_outs. This is only for no of time the date is pushed out (Date incremented) not pulled in.

SELECT SO_NUMBER, REV_NUMBER, LINE_NUMBER, RS_DATE, <> no_of_push_outs
FROM zzenp_so_multi_rs
WHERE status = 'Open'

enter image description here

CodePudding user response:

This is how I understood it.

The temp CTE calculates previous rs_date, and it is then used to sum push-outs (as you can't have analytic function within the sum aggregation).

SQL> WITH
  2     temp
  3     AS
  4        (SELECT so_number,
  5                rev_number,
  6                line_number,
  7                rs_date,
  8                status,
  9                LAG (rs_date) OVER (PARTITION BY so_number ORDER BY rev_number) prev_rs_date
 10           FROM zzenp_so_multi_rs)
 11    SELECT z.so_number,
 12           z.line_number,
 13           (SELECT MAX (b.rev_number)
 14              FROM zzenp_so_multi_rs b
 15             WHERE     b.so_number = z.so_number
 16                   AND b.status = 'Open') rev_number,
 17           (SELECT MAX (b.rs_date)
 18              FROM zzenp_so_multi_rs b
 19             WHERE     b.so_number = z.so_number
 20                   AND b.status = 'Open') rs_date,
 21           SUM (CASE WHEN z.rs_date > z.prev_rs_date THEN 1 ELSE 0 END) l_sum
 22      FROM temp z
 23  GROUP BY z.so_number, z.line_number
 24  ORDER BY z.so_number;

SO_NUMBER                      LINE_NUMBER REV_NUMBER RS_DATE         L_SUM
------------------------------ ----------- ---------- ---------- ----------
10000                                    1          6 17.05.2022          2
10001                                    1          5 13.05.2022          1

SQL>

CodePudding user response:

For Oracle version 12.1 and later, you can use match_recognize for a clean, elegant solution.

select so_number, rev_number, line_number, rs_date, no_of_push_outs
from   zzenp_so_multi_rs
match_recognize (
  partition by so_number, line_number
  order     by rev_number
  measures  last(rev_number) as rev_number,
            count(up.*)      as no_of_push_outs,
            last(rs_date)    as rs_date
  pattern   ( (up|other)* )
  define    up as rs_date > prev(rs_date)
);

CodePudding user response:

Also using LAG() to get number of date increases, but hopefully simpler join

with pout as (
select so_number, count(*) no_of_push_outs  from (
select z.so_number, rs_date, 
lag(rs_date) over (partition by so_number order by rev_number) p_rs_date
from zzenp_so_multi_rs z
)
where rs_date > p_rs_date
group by so_number
)
select z.*, pout.no_of_push_outs
from zzenp_so_multi_rs z, pout
where z.so_number=pout.so_number
and z.status='Open';

CodePudding user response:

You can do it with LAG and the COUNT analytic functions (without any self-joins):

SELECT *
FROM   (
  SELECT so_number,
         rev_number,
         line_number,
         rs_date,
         status,
         COUNT(is_push_out) OVER (PARTITION BY so_number) AS no_of_push_outs
  FROM    (
    SELECT z.*,
           CASE
           WHEN LAG(rs_date) OVER (PARTITION BY so_number ORDER BY rev_number)
                  < rs_date
           THEN 1
           END AS is_push_out
    FROM   zzenp_so_multi_rs z
  )
)
WHERE  status = 'Open';

Or, you can use the LAG analytic function and then use GROUP BY and KEEP (DENSE_RANK LAST ORDER BY rev_number) to get the data for the last revision in an aggregation function:

SELECT so_number,
       MAX(rev_number) AS rev_number,
       MAX(line_number) KEEP (DENSE_RANK LAST ORDER BY rev_number)
         AS line_number,
       MAX(rs_date) KEEP (DENSE_RANK LAST ORDER BY rev_number)
         AS rs_date,
       MAX(status) KEEP (DENSE_RANK LAST ORDER BY rev_number)
         AS status,
       COUNT(is_push_out) AS no_of_push_outs
FROM    (
  SELECT z.*,
         CASE
         WHEN LAG(rs_date) OVER (PARTITION BY so_number ORDER BY rev_number)
                < rs_date
         THEN 1
         END AS is_push_out
  FROM   zzenp_so_multi_rs z
)
GROUP BY so_number;

Which, for the sample data, both output:

SO_NUMBER REV_NUMBER LINE_NUMBER RS_DATE STATUS NO_OF_PUSH_OUTS
10000 6 1 17-MAY-22 Open 2
10001 5 1 13-MAY-22 Open 1

db<>fiddle here

  • Related