需要 Oracle SQL 中的日期增量数

Need to number of Date increments in Oracle SQL

需要 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');

在这里,我们有销售订单号、修订号、行号、RS 日期和状态。每修改一行,插入一条记录,状态修改为引用旧记录&打开新记录。

我需要 no_of_push_outs 的计算函数/子查询。这仅适用于日期被推出(日期递增)而不是被拉入的时间。

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

我是这样理解的

temp CTE 计算之前的rs_date,然后用它来求和push-outs(因为你不能有解析sum 聚合中的函数)。

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>

对于 Oracle 12.1 及更高版本,您可以使用 match_recognize 来获得干净、优雅的解决方案。

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)
);

还使用 LAG() 获取日期数量增加,但希望更简单的加入

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';

您可以使用 LAGCOUNT 分析函数(没有任何 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';

或者,您可以使用 LAG 分析函数,然后使用 GROUP BYKEEP (DENSE_RANK LAST ORDER BY rev_number) 获取聚合函数中最后修订的数据:

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;

其中,对于示例数据,都输出:

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