根据给定条件计算剩余运行余额的 SQL 查询 [英] SQL Query to calculate remaining running balances based on a given conditions

查看:21
本文介绍了根据给定条件计算剩余运行余额的 SQL 查询的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个这样的股票交易表:

I have a stock transaction table like this:

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 交易计算剩余余额,如下所示:

Each of my IN transactions has price associated to it and a batch number (lot number). Now I would like to calculate the remaining quantity by First In First Out (FIFO) rule, meaning the first in should be adjusted with first out. After adjusting the quantities the remaining balances are to be calculated against each IN transaction for the same item as shown below:

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.从剩余数量可以得出该值.

As we can see from the above table for item ABC, after adjusting (125 + 100) OUT qty against the IN qty (100 + 50 + 75) using FIFO the quantity remaining for the batch 71001000 is 0, 71001001 is 25 and for batch 71001002 is 75. From the remaining quantity the value can be derived.

请帮助我使用任何方法(基于光标或 CTE 或 JOINS 等)来实现这一点在此先感谢您的帮助.

Please help me to achieve this using any of the methods (either cursor based or CTE or JOINS, etc) Thanks in advance for the help.

StockOverflow 的一位用户提出了这个答案:

One of the users of StockOverflow suggested this answer:

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有问题,结果附在这里 取值的记录不匹配以黄色表示.请帮忙解决问题.

This sql is having a problem and the result is attached here The records for which the value are not matching are indicated in yellow color. Kindly help to solve the problem.

推荐答案

我认为这应该可以解决问题?

I think this should do the trick?

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

这篇关于根据给定条件计算剩余运行余额的 SQL 查询的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆