2012-05-11 15 views
0

は、私はこのような在庫トランザクションテーブルを持っている:SQLクエリ与えられた条件に基づいて、残りの実行中の残高を計算する

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のための上記の表から、(+ 100 125)を調整した後に見ることができるようにFIFOを使用するIN qty(100 + 50 + 75)に対して、バッチ71001000の残量は0、71001001は25、バッチ71001002は75です。残りの数量から値を導き出すことができます。

これを実現するには、カーソルベースまたはCTEまたはJOINSなどの方法を使用してください。 ご協力いただきありがとうございます。

StockOverflowのユーザの一つは、この回答を示唆:

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は、問題を有するされ、結果は値が一致されていないためQuery Resultレコードが黄色で示され、ここで取り付けられています。親切にも問題の解決に役立ちます。

+1

明白な質問は、バッチ番号がOUTレコードに割り当てられていない理由です。あなたの問題をもっと簡単に解決することができます。あなたの質問は明らかに関係を示していますが、テーブルの定義にはこれが反映されていません。 – Brad

+0

こんにちは@ブラッドは、バッチ番号は、多くを識別するために作成されたトランザクション番号です。しかし、すべてのロットは物理的に混合されて発行されます。しかし、会計目的のためには結果が必要です。 – Nagesh

+0

@Nageshサンプルデータの下で元の答えを変更しました – Dibstar

答えて

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 
+0

親愛なる@Davin、答えに感謝し、あなたが最初の解決策を出したのはあなたです。あなたにすべてのクレジット。これを確認して確認しましょう。 – Nagesh

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' 

のようなあなたが自分自身に、テーブルに参加する必要があり、これを達成するために結果は、あなたの質問からABCのための最初の5つのレコードに次のように表示されます。

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

左は、レコード内のそれぞれのStockIDは常にOUT関連付けられたレコードより1つの少ない数であることを前提とした作品に参加します。個人的には、データモデルの改善が必要だと思います。

  • OUTレコードはBatchNoが割り当てられている必要がありますまたはレコード
  • 内の関連の StockIDへの参照が同じにoccuring IN/OUT処理するためのDateTimeフィールドを追加し、順次発注のため
  • をタイムスタンプフィールドを追加します日
+0

こんにちは@Brad、timestampおよびDatetimeはデータモデルに存在し、ここでは簡単にするために示していません。しかし、BatchNo参照は存在せず、これがデータモデルの設計方法です。必要な結果を達成するために親切に助けてください。 – Nagesh

+0

もう少し論理を明確にすることができれば、私はさらに答えをとろうとすることができます。私はあなたの希望の結果の最初のレコードがBatchNo 71001000のIN = 200とOUT = 100のときに 'RemainingQty = 0'を持つ理由を理解していません。' RemainingQty = 100'を期待しました。 – Brad

+0

返信@Bradに感謝します。項目ABCには、5つのトランザクションがあります.3つのINと2つのOUTです。すべてのINからの正味流入量は325であり、OUTからの正味流出量は225であり、残りのネットは100である。この100個の量はFIFOに基づいて各バッチに割り当てられる。 200個のQtyは最初のINトランザクションであるため、取り消されます。 – Nagesh

関連する問題