递归 CTE,用于获取上一条记录的收盘值作为下一条记录的开盘值

问题描述 投票:0回答:1

我有两个表如下:

表 1:按日期发出收据

werks  matnr  budat    Issue   Receipt
  p1    m1  05-Apr-24   100     40
  p1    m1  29-Apr-24   300     0
  p1    m1  12-May-24   20      450
  p1    m1  21-May-24   308     526
  p1    m1  01-Jun-24   74      289
  p1    m1  15-Jun-24   380     103
  p1    m1  21-Jun-24   411     301
  p1    m1  07-Jul-24   147     0
  p1    m1  13-Jul-24   264     327
  p1    m1  14-Jul-24   465     119
  p2    m2  01-Apr-24   503     550
  p2    m2  08-Apr-24   0       355
  p2    m2  29-Apr-24   238     597
  p2    m2  12-May-24   473     564
  p2    m2  21-May-24   0       539
  p2    m2  15-Jun-24   0       360
  p2    m2  21-Jun-24   487     294
  p2    m2  13-Jul-24   275     0

表2:截至2024年3月31日的期末库存。这将是 m1 或 m2 第一个交易日期的未平仓股票。

WERKS   MATNR   BUDAT    ClsStock
  p1    m1    31/03/2024    10
  p2    m2    31/03/2024    0

目标:我想创建一个如下表,其中前一天的收盘股票将是当前日期的开盘股票。

Closing Stock = Open + Receipts - Issue.

因此决赛桌应如下所示:

WERKS  MATNR    BUDAT       Open    Issue  Receipts  Close
 p1     m1      05-Apr-24    10     100     40      -50      ---- Please note that open stock it is coming from OpenStock Table
 p1     m1      29-Apr-24   -50     300     0       -350     ---- Closing stock as on 5th April becomes the open stock
 p1     m1      12-May-24   -350    20      450      80
 p1     m1      21-May-24   80      308     526     298
 p1     m1      01-Jun-24   298     74      289     513
 p1     m1      15-Jun-24   513     380     103     236
 p1     m1      21-Jun-24   236     411     301     126
 p1     m1      07-Jul-24   126     147     0       -21
 p1     m1      13-Jul-24   -21     264     327     42
 p1     m1      14-Jul-24   42      465     119     -304
 p2     m2      01-Apr-24   0       503     550     47
 p2     m2      08-Apr-24   47      0       355     402
 p2     m2      29-Apr-24   402     400     300     302
 p2     m2      12-May-24   302     473     250     79
 p2     m2      21-May-24   79      0       539     618
 p2     m2      15-Jun-24   618     0       360     978
 p2     m2      21-Jun-24   978     200     350     1128
 p2     m2      13-Jul-24   1128    275     0       853
 p2     m2      31-Jul-24   853     201     552     1204

有了上述要求,下面是代码片段

---Step 1: We create a temp table that UNION open and issue receipts---
select * into #OpenIssueRece from
(
    select distinct
        ir.matnr
        ,ir.mtart
        ,ir.werks
        ,ir.budat_mkpf
        ,ir.OpenQty
        ,ir.IssueQty
        ,ir.ReceQty
    from #table-1 ir 
    union all 
    select distinct
        o.xmatnr        as matnr
        ,o.mtart        as mtart
        ,o.werk         as werks
        ,o.budat_mkpf   as budat_mkpf
        ,o.OpenQty      as OpenQty 
        ,0              as IssueQty 
        ,0              as ReceQty
    from #Table-2 o
);

--Step 2: Recursive CTE----


with recursive inventorycte(matnr,werks,budat_mkpf,OpenQty, IssueQty, ReceQty, CloseQty,rn) as
(
    select 
        matnr 
        ,werks 
        ,budat_mkpf
        ,cast(Open as numeric(18,2)) as OpenQty
        ,cast(Issue as numeric(18,2)) as IssueQty
        ,cast(Receipts as numeric(18,2)) as ReceQty
        ,cast(Open + Receipts - Issue as numeric(18,2)) as Close
        ,row_number() over(partition by matnr,werks order by budat_mkpf,bwart) rn
       
        from #OpenIssueRece 
        where 
            (matnr,werks,budat_mkpf) in 
                (
                    select matnr,werks,min(budat_mkpf)
                    from #OpenIssueRece
                    group by 1,2
                )


    union all  
    
        select 
            curr.matnr
            ,curr.werks  
            ,curr.budat_mkpf
            ,cast(prev.CloseQty as numeric(18,2)) as OpenQty
            ,curr.IssueQty 
            ,curr.ReceQty
            ,cast(prev.CloseQty + curr.ReceQty - curr.IssueQty as numeric(18,2)) as CloseQty
            ,curr.rn_1 as rn

            from inventorycte prev
            inner join 
                (
                select 
                    matnr 
                    ,werks 
                    ,budat_mkpf
                    ,cast(OpenQty as numeric(18,2)) as OpenQty
                    ,cast(IssueQty as numeric(18,2)) as IssueQty
                    ,cast(ReceQty as numeric(18,2)) as ReceQty
                    ,row_number() over(partition by matnr,werks order by budat_mkpf,bwart) rn_1
                    from #OpenIssueRece
                ) curr 
                on ltrim(curr.matnr,'0') = ltrim(prev.matnr,'0')
                and curr.werks = prev.werks 
                ---and curr.budat_mkpf > prev.budat_mkpf --It is commented. Do we need this? 
                and cast(curr.rn_1 as int) = cast(prev.rn as int)+1
            )
 select 
  matnr
  ,werks 
  ,budat_mkpf 
  ,rn
  ,sum(OpenQty) as OpenQty 
  ,sum(IssueQty) as IssueQty
  ,sum(ReceQty) as RecQty
  ,sum(CloseQty) as CloseQty

  into #finalORIC
  from inventorycte
  group by 1,2,3,4,5,6
  order by matnr, werks,budat_mkpf;

现在问题陈述:

在表#finalORIC中,发行和收货数量翻倍。为什么?是因为

UNION
还是有任何
CROSS JOIN
发生?

请注意上述查询要在 Redshift 上运行。

sql amazon-redshift
1个回答
0
投票

因此,此类问题通常不是递归 CTE 的良好用例。 递归有深度限制,除非可以保证未来的计算链小于这个深度,否则最好走不同的路线。

使用窗口函数展开计算的最佳方法。 这比递归更容易保持直线且速度更快。 我将在这里发布代码,因为我认为它足够简单,但如果不是,请提问。

请注意,2024 年 4 月 29 日的源数据存在数据差异。 您对此数据的表 1 的定义是:

p2 m2 29-4-24 238 597

虽然您的预期结果是:

p2 m2 29-4-24 402 400 300 302

我采用了表 1 的定义,因此在此之后事情与您的预期不符。

用于数据设置和查询的SQL:

create table table_1 (
  werks  varchar(4),
  matnr  varchar(4),
  budat    date,
  Issue   int,
  Receipt int);

  insert into table_1 values 
('p1', 'm1', '05-Apr-2024', 100, 40),
('p1', 'm1', '29-Apr-2024', 300, 0),
('p1', 'm1', '12-May-2024', 20, 450),
('p1', 'm1', '21-May-2024', 308, 526),
('p1', 'm1', '01-Jun-2024', 74, 289),
('p1', 'm1', '15-Jun-2024', 380, 103),
('p1', 'm1', '21-Jun-2024', 411, 301),
('p1', 'm1', '07-Jul-2024', 147, 0),
('p1', 'm1', '13-Jul-2024', 264, 327),
('p1', 'm1', '14-Jul-2024', 465, 119),
('p2', 'm2', '01-Apr-2024', 503, 550),
('p2', 'm2', '08-Apr-2024', 0, 355),
('p2', 'm2', '29-Apr-2024', 238, 597),
('p2', 'm2', '12-May-2024', 473, 564),
('p2', 'm2', '21-May-2024', 0, 539),
('p2', 'm2', '15-Jun-2024', 0, 360),
('p2', 'm2', '21-Jun-2024', 487, 294),
('p2', 'm2', '13-Jul-2024', 275, 0);

create table table_2 (
  WERKS   varchar(4),
  MATNR   varchar(4),
  BUDAT    date,
  ClsStock int
);

insert into table_2 values
  ('p1',    'm1',    '2024-03-31',    10),
  ('p2',    'm2',    '2024-03-31',    0);

with dataset as (
  select o.werks, o.matnr, o.budat, 0 Issue, 0 Receipt, ClsStock orig_close
  from Table_2 o
  union all 
  select ir.werks,  ir.matnr,  ir.budat, ir.Issue, ir.Receipt, 0 orig_close
  from table_1 ir
  ),
processed_data as (
  select *,
    sum(issue) over(partition by werks, matnr order by budat rows between unbounded preceding and 1 preceding) as sum_issue,
    sum(receipt) over(partition by werks, matnr order by budat rows between unbounded preceding and 1 preceding) as sum_receipt,
    sum(orig_close) over(partition by werks, matnr) + sum_receipt - sum_issue new_open, 
    new_open + receipt - issue new_close
  from dataset)
select werks, matnr, budat, new_open "Open", Issue, Receipt, new_close "Close"
from processed_data
where new_close is not NULL
order by werks, matnr, budat;
© www.soinside.com 2019 - 2024. All rights reserved.