2012-05-11 70 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 

每個我的交易已經價格相關聯,並批號(批號)。現在我想通過先入先出(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上表中,調整(125 + 100)後OUT見數量與使用FIFO的IN數量(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

要問的一個顯而易見的問題是爲什麼你沒有將BatchNo分配給OUT記錄?這會讓事情更容易解決你的問題。你的問題清楚地說明了這種關係,但是你的表格定義並不反映這一點。 – Brad

+0

Hi @Brad批號只是一個創建的交易號碼,用於標識很多。但是,所有這些地塊都是混在一起發行的。但爲了會計目的,結果是必需的。 – 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

親愛的@達文,謝謝你的回答,你是第一個解決方案的人。所有學分給你。讓我檢查並確認這一點。 – 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' 

結果將顯示你從你的問題前5條記錄爲ABC以下。

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

左側加入假設作品的StockID對中的每個記錄總是少了一個數比對應的輸出記錄。我個人認爲你的數據模型需要改進。

  • OUT記錄應該有分配BatchNo或訂購
  • 添加日期時間字段用於處理IN/OUT存在的對同來的在創紀錄的
  • 關聯添加時間戳字段順序的 StockID參考天
+0

Hi @Brad,時間戳和日期時間存在於數據模型中,爲簡單起見,此處未顯示。但是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