0

次のような株式取引テーブルがあります。

StockID Item  TransDate   TranType  BatchNo Qty Price 
10001   ABC   01-Apr-2012   IN     71001000 200  750.0
10002   ABC   02-Apr-2012   OUT             100       
10003   ABC   03-Apr-2012   IN     71001001  50  700.0
10004   ABC   04-Apr-2012   IN     71001002  75  800.0
10005   ABC   10-Apr-2012   OUT             125       
10006   XYZ   05-Apr-2012   IN     71001003 150  350.0
10007   XYZ   05-Apr-2012   OUT             120       
10008   XYZ   15-Apr-2012   OUT              10       
10009   XYZ   20-Apr-2012   IN     71001004  90  340.0
10010   PQR   06-Apr-2012   IN     71001005  50  510.0
10011   PQR   15-Apr-2012   IN     71001006  60  505.0
10012   MNO   01-Apr-2012   IN     71001007  76  410.0
10013   MNO   11-Apr-2012   OUT              76 

私の IN トランザクションには、価格とバッチ番号 (ロット番号) が関連付けられています。ここで、先入れ先出し (FIFO) ルールによって残りの数量を計算したいと思います。つまり、先入れ先出しで調整する必要があります。数量を調整した後、残りの残高は、以下に示すように、同じアイテムの各 IN トランザクションに対して計算されます。

StockID Item  TransDate   TranType  BatchNo Qty Price  RemainingQty
10001   ABC   01-Apr-2012   IN     71001000 200  750.0    0        
10002   ABC   02-Apr-2012   OUT             100             
10003   ABC   03-Apr-2012   IN     71001001  50  700.0   25        
10004   ABC   04-Apr-2012   IN     71001002  75  800.0   75        
10005   ABC   10-Apr-2012   OUT             125             
10006   XYZ   05-Apr-2012   IN     71001003 150  350.0   20        
10007   XYZ   05-Apr-2012   OUT             120             
10008   XYZ   15-Apr-2012   OUT              10             
10009   XYZ   20-Apr-2012   IN     71001004  90  340.0   90        
10010   PQR   06-Apr-2012   IN     71001005  50  510.0   50        
10011   PQR   15-Apr-2012   IN     71001006  60  505.0   60        
10012   MNO   01-Apr-2012   IN     71001007  76  410.0   0         
10013   MNO   11-Apr-2012   OUT              76                    

上記の品目 ABC の表からわかるように、FIFO を使用して (125 + 100) OUT 数量を IN 数量 (100 + 50 + 75) に対して調整した後、バッチ 71001000 の残り数量は 0、71001001 は 25 であり、バッチ71001002 は 75 です。残りの数量から値を導き出すことができます。

いずれかの方法(カーソルベース、CTE、JOINSなど)を使用してこれを達成するのを手伝ってください。助けてくれてありがとう。

StockOverflow のユーザーの 1 人がこの回答を提案しました。

SELECT 10001   as stockid,'ABC' as item,'01-Apr-2012' as transdate,'IN' as trantype,     71001000 as batchno, 200 as qty,  750.0  as price INTO #sample
UNION ALL SELECT 10002   ,'ABC','02-Apr-2012','OUT', NULL            ,100,NULL        
UNION ALL SELECT 10003   ,'ABC','03-Apr-2012','IN',     71001001,  50 , 700.0 
UNION ALL SELECT 10004   ,'ABC','04-Apr-2012','IN',     71001002,  75 , 800.0 
UNION ALL SELECT 10005   ,'ABC','10-Apr-2012','OUT',     NULL        ,125,NULL        
UNION ALL SELECT 10006   ,'XYZ','05-Apr-2012','IN',     71001003, 150 , 350.0 
UNION ALL SELECT 10007   ,'XYZ','05-Apr-2012','OUT',      NULL      , 120    ,NULL    
UNION ALL SELECT 10008   ,'XYZ','15-Apr-2012','OUT',       NULL     ,  10        ,NULL
UNION ALL SELECT 10009   ,'XYZ','20-Apr-2012','IN',     71001004,  90 , 340.0 
UNION ALL SELECT 10010   ,'PQR','06-Apr-2012','IN',     71001005,  50 , 510.0 
UNION ALL SELECT 10011   ,'PQR','15-Apr-2012','IN',     71001006,  60 , 505.0 
UNION ALL SELECT 10012   ,'MNO','01-Apr-2012','IN',     71001007,  76 , 410.0 
UNION ALL SELECT 10013   ,'MNO','11-Apr-2012','OUT',    NULL    ,76 ,NULL


;WITH remaining AS
(
    SELECT *,
           CASE 
                WHEN trantype = 'IN' THEN 1
                ELSE -1
           END * qty AS stock_shift,
           ROW_NUMBER() OVER(PARTITION BY item ORDER BY transdate) AS row,
           CASE 
                WHEN trantype = 'OUT' THEN NULL
                ELSE ROW_NUMBER()OVER(PARTITION BY item, CASE WHEN trantype = 'IN' THEN 0 ELSE 1 END ORDER BY transdate)
           END AS in_row,
           SUM(CASE WHEN trantype = 'OUT' THEN qty END) OVER(PARTITION BY item) AS total_out
    FROM   #sample
)
,remaining2 AS
(
    SELECT r1.item,
           r1.stockid,
           MAX(r1.transdate) AS transdate,
           MAX(r1.trantype) AS trantype,
           MAX(r1.batchno) AS batchno,
           MAX(r1.qty) AS qty,
           MAX(r1.price) AS price,
           MAX(r1.total_out) AS total_out,
           MAX(r1.in_row) AS in_row,
           CASE 
                WHEN MAX(r1.trantype) = 'OUT' THEN NULL
                WHEN SUM(CASE WHEN r1.trantype = 'IN' THEN r2.qty ELSE 0 END) - MAX(r1.total_out) < 0 THEN SUM(CASE WHEN r1.trantype = 'IN' THEN r2.qty ELSE 0 END) 
                     - MAX(r1.total_out)
                ELSE 0
           END AS running_in
    FROM   remaining r1
           LEFT OUTER JOIN remaining r2
                ON  r2.row <= r1.row
                AND r2.item = r1.item
    GROUP BY
           r1.item,
           r1.stockid
)
SELECT r2.item,
       r2.stockid,
       MAX(r2.transdate) AS transdate,
       MAX(r2.trantype) AS trantype,
       MAX(r2.batchno) AS batchno,
       MAX(r2.qty) AS qty,
       MAX(r2.price) AS price,
       MAX(CASE WHEN r2.trantype = 'OUT' THEN NULL ELSE ISNULL(r2.qty + r3.running_in, 0) END) AS remaining_stock
FROM   remaining2 r2
       LEFT OUTER JOIN remaining2 r3
            ON  r2.in_row - 1 = r3.in_row
            AND r2.item = r3.item
GROUP BY
       r2.item,
       r2.stockid

この sql に問題があり、結果がここに添付されクエリ結果ています。値が一致しないレコードは黄色で示されます。問題の解決にご協力ください。

4

2 に答える 2

1

私はこれがトリックを行うべきだと思いますか?

SELECT 10001   as stockid,'ABC' as item,'01-Apr-2012' as transdate,'IN' as trantype,     71001000 as batchno, 200 as qty,  750.0  as price INTO #sample
UNION ALL SELECT 10002   ,'ABC','02-Apr-2012','OUT', NULL            ,100,NULL        
UNION ALL SELECT 10003   ,'ABC','03-Apr-2012','IN',     71001001,  50 , 700.0 
UNION ALL SELECT 10004   ,'ABC','04-Apr-2012','IN',     71001002,  75 , 800.0 
UNION ALL SELECT 10005   ,'ABC','10-Apr-2012','OUT',     NULL        ,125,NULL        
UNION ALL SELECT 10006   ,'XYZ','05-Apr-2012','IN',     71001003, 150 , 350.0 
UNION ALL SELECT 10007   ,'XYZ','05-Apr-2012','OUT',      NULL      , 120    ,NULL    
UNION ALL SELECT 10008   ,'XYZ','15-Apr-2012','OUT',       NULL     ,  10        ,NULL
UNION ALL SELECT 10009   ,'XYZ','20-Apr-2012','IN',     71001004,  90 , 340.0 
UNION ALL SELECT 10010   ,'PQR','06-Apr-2012','IN',     71001005,  50 , 510.0 
UNION ALL SELECT 10011   ,'PQR','15-Apr-2012','IN',     71001006,  60 , 505.0 
UNION ALL SELECT 10012   ,'MNO','01-Apr-2012','IN',     71001007,  76 , 410.0 
UNION ALL SELECT 10013,'MNO','11-Apr-2012','OUT',          NULL    ,76 ,NULL

;with remaining_stock as
( 
SELECT * 
,CASE WHEN trantype = 'IN' THEN 1 ELSE -1 END * qty AS stock_shift
,row_number() OVER (PARTITION BY item ORDER BY transdate) as row
,CASE WHEN trantype = 'OUT' THEN NULL ELSE
row_number()OVER (PARTITION BY item,CASE WHEN trantype = 'IN' THEN 0 ELSE 1 END ORDER BY transdate) END as in_row
,CASE WHEN trantype = 'IN' THEN NULL ELSE
row_number()OVER (PARTITION BY item,CASE WHEN trantype = 'OUT' THEN 0 ELSE 1 END ORDER BY transdate) END as out_row
,ISNULL(SUM(CASE WHEN trantype = 'OUT' THEN qty END) OVER (PARTITION BY item),0) AS total_out
,ISNULL(SUM(CASE WHEN trantype = 'IN' THEN qty END) OVER (PARTITION BY item),0) AS total_in
FROM #sample
)
,remaining_stock2 AS
(
SELECT 
r1.item
,r1.stockid
,MAX(r1.transdate) as transdate
,MAX(r1.trantype) as trantype
,MAX(r1.batchno) as batchno
,MAX(r1.qty) as qty
,MAX(r1.price) as price
,MAX(r1.total_in) as total_in
,MAX(r1.total_out) as total_out
,SUM(r2.qty) as running_in
FROM remaining_stock r1 
LEFT OUTER JOIN remaining_stock r2 on r2.in_row <= r1.in_row
                    AND r2.item = r1.item       
GROUP BY
r1.item
,r1.stockid 
)
SELECT
item
,stockid
,transdate
,trantype
,batchno
,qty
,price
,CASE WHEN  trantype = 'OUT' THEN NULL
        WHEN total_out >= running_in THEN 0 
        WHEN (running_in - total_out) < qty THEN (running_in - total_out)
        WHEN (running_in - total_out) >= qty THEN qty 
        END as remaining_stocks
FROM remaining_stock2
于 2012-05-11T11:57:01.177 に答える
0

あなたの質問は、FIFO ロジックがどのように適用されるかについて、私にはあまり明確ではありません。IN次のレコードが存在する場合、各レコードを次のレコードに関連付けたいと仮定しますOUT。これを実現するには、次のようにテーブル自体を結合する必要があります

select
    t1.BatchNo,
    isnull(t1.Qty,0)  as 'IN Qty',
    isnull(t2.Qty,0)  as 'OUT Qty',
    isnull(t1.Qty,0) - isnull(t2.Qty,0) as 'Remaining Qty'
from 
    tbl_test t1
left join tbl_test t2
    on t2.StockID = (t1.StockID + 1)
    and t2.TranType = 'OUT'
where
    t1.TranType = 'IN'

結果は、質問の最初の 5 つのレコードについて次のように表示さABCれます。

BatchNo  | IN Qty | OUT Qty | Remaining Qty
71001000 | 200    | 100     | 100
71001001 | 50     | 0       | 50
71001002 | 75     | 125     | -50

左結合は、各 IN レコードの StockID が、関連付けられた OUT レコードよりも常に 1 つ少ない数値であるという前提で機能します。個人的には、データ モデルを改善する必要があると思います。

  • OUT レコードには BatchNo が割り当てられているか、関連する IN レコードの StockID への参照が必要です
  • 順番に並べるためのタイムスタンプ フィールドを追加する
  • 同じ日に発生する IN/OUT を処理するための DateTime フィールドを追加します
于 2012-05-11T09:56:25.833 に答える