我有两个表如下:
表 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 上运行。
因此,此类问题通常不是递归 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;