このサイトを検索して得た最も近いものは次のとおりです 。SQLでの在庫平均コスト計算
しかし残念ながら、それはオラクル固有であり、モデル句を使用していました。
それでは始めましょう。
2 つのテーブルがあります:
-在庫トランザクションを保持する
テーブルと
、最新の在庫評価を保持するテーブル
特定の日付に基づく平均原価計算法を使用して、在庫評価レポートを作成しようとしています。最初からその特定の日付までを通常の方法で計算すると、さまざまな応答時間が得られます。
5 年分のデータ (および何千もの異なる在庫品目) を計算することを想像してみてください。かなりの時間がかかります (私の会社はシリコンバレー グレードではありません。つまり、2 コア CPU と 8 GB の RAM のみです)。そのため、最新 (現在) のバックトラックからその特定の日付まで逆算しています。
(毎月、経理部がデータをチェックするので、計算は1か月分のデータのみを永遠に処理します。一貫した不変のパフォーマンスに等しい)
以下のスクリプトでテーブルを1つにマージしました
create table test3 ( rn integer, amt numeric, qty integer, oqty integer);
insert into test3 (rn,amt,qty,oqty) values (0,2260038.16765793,8,0);
insert into test3 (rn,amt,qty,oqty) values (1,1647727.2727,3,0);
insert into test3 (rn,amt,qty,oqty) values (2,2489654.75326715,0,1);
insert into test3 (rn,amt,qty,oqty) values (3,2489654.75326715,0,1);
insert into test3 (rn,amt,qty,oqty) values (4,1875443.6364,1,0);
insert into test3 (rn,amt,qty,oqty) values (5,1647727.2727,3,0);
insert into test3 (rn,amt,qty,oqty) values (6,3012987.01302857,0,1);
insert into test3 (rn,amt,qty,oqty) values (7,3012987.01302857,0,1);
select * from test3; (already sorted desc so rn=1 is the newest transaction)
rn amt qty oqty
0 2260038.168 8 0 --> this is the current average
1 1647727.273 3 0
2 2489654.753 0 1
3 2489654.753 0 1
4 1875443.636 1 0
5 1647727.273 3 0
6 3012987.013 0 1
7 3012987.013 0 1
with recursive
runsum (id,amt,qty,oqty,sqty,avg) as
(select data.id, data.amt, data.qty, data.oqty, data.sqty, data.avg
from (
select rn as id,amt,qty, oqty,
sum(case when rn=0 then qty else
case when oqty=0 then qty*-1
else oqty end end) over (order by rn) as sqty, lag(amt) over (order by rn) as avg
from test3 ) data
),
trans (id,amt,qty,oqty,sqty,prevavg,avg) as
(select id,amt,qty,oqty, sqty,avg,avg
from runsum
union
select runsum.id,trans.amt,trans.qty, trans.oqty, trans.sqty, lag(trans.avg) over (order by 1),
case when runsum.sqty=0 then runsum.amt else
((trans.prevavg*(runsum.sqty+trans.qty))-(runsum.amt*trans.qty)+(trans.prevavg*trans.oqty))/(runsum.sqty+trans.oqty)
end
from runsum join trans using (id))
select *
from trans
where prevavg is null and avg is not null
order by id;
結果はこのようになっているはずです
rn amt qty oqty sum avg
1 1647727.273 3 0 5 2627424.705
2 2489654.753 0 1 6 2627424.705
3 2489654.753 0 1 7 2627424.705
4 1875443.636 1 0 6 2752754.883
5 1647727.273 3 0 3 3857782.493
6 3012987.013 0 1 4 3857782.493
7 3012987.013 0 1 5 3857782.493
しかし、代わりに私はこれを得る
id amt qty oqty sqty avg
1 1647727.273 3 0 5 2627424.705
2 2489654.753 0 1 6 2627424.705
3 2489654.753 0 1 7 2627424.705
5 1647727.273 3 0 3 3607122.137 --> id=4 is missing thus
screwing the calculation
and id=6 in turn dissappears tpp
7 3012987.013 0 1 5 3607122.137
私はびっくりしています。間違いはどこですか?
ご親切にありがとうございました。
編集済み
平均原価計算方法のバックトラッキング (現在の平均を指定して、最後のトランザクションの平均を計算し、n 番目のトランザクションまで同様に計算します)
Avg (n) = ((Avg(n-1) * (Cum Qty(n)+In Qty(n))) - (In Amount(n) * In Qty (n)) + (Avg(n-1) * Out Qty(n))/(Cum Qty(n)+Out Amount(n))
バックトラック トランザクションの累積数量は、インの場合はマイナス、アウトの場合はプラスになります。したがって、現在の数量が 8 の場合、前の数量のトランザクションは 3 であり、そのトランザクションの累積数量は 5 です。
直前の 1 つのトランザクションの平均を計算するには、現在の平均を使用してそのトランザクションの計算に使用します。
@kordirkoの助けによる現在の回答
with recursive
runsum (id,amt,qty,oqty,sqty,avg) as
(select data.id, data.amt, data.qty, data.oqty, data.sqty, data.avg
from (
select rn as id,amt,qty, oqty,
sum(case when rn=0 then qty else
case when oqty=0 then qty*-1
else oqty end end) over (order by rn) as sqty, lag(amt) over (order by rn) as avg
from test3 ) data
),
counter (maximum) as
(select count(rn)
from test3
),
trans (n, id,amt,qty,oqty,sqty,prevavg,avg) as
(select 0 n, id,amt,qty,oqty, sqty,avg,avg
from runsum
union
select trans.n+1, runsum.id,trans.amt,trans.qty, trans.oqty, trans.sqty,
lag(trans.avg) over (order by 1),
case when runsum.sqty=0 then runsum.amt else
((trans.prevavg*(runsum.sqty+trans.qty))-(runsum.amt*trans.qty)+(trans.prevavg*trans.oqty))/(runsum.sqty+trans.oqty)
end
from runsum join trans using (id)
where trans.n<(select maximum*2 from counter))
select *
from trans
where prevavg is null and avg is not null
order by id;