MS SQL FIFO部分传输

MS SQL FIFO部分传输,sql,sql-server,fifo,Sql,Sql Server,Fifo,我有许多交易,将库存从一个账户转移到另一个账户。我可以转移所有库存,也可以转移部分库存 我需要在我的佣金日期向存货所在账户的所有者支付佣金 我的报告需要显示库存项目的原始来源(如果它们已转移),并提供我可以计算佣金的单位余额 交易示例: 账户100 账户,trxid,已交易单位,交易类型,转帐人,转帐人,日期 100,1100,买入,无效,无效,2020年1月1日 100,2,50,转入,200,空,1/2/2020 账户200 账户,trxid,已交易单位,交易类型,转帐人,转帐人,日期 20

我有许多交易,将库存从一个账户转移到另一个账户。我可以转移所有库存,也可以转移部分库存

我需要在我的佣金日期向存货所在账户的所有者支付佣金

我的报告需要显示库存项目的原始来源(如果它们已转移),并提供我可以计算佣金的单位余额

交易示例:

账户100
账户,trxid,已交易单位,交易类型,转帐人,转帐人,日期
100,1100,买入,无效,无效,2020年1月1日
100,2,50,转入,200,空,1/2/2020

账户200
账户,trxid,已交易单位,交易类型,转帐人,转帐人,日期
200,3,40,买入,无效,无效,2019年12月1日
200,4,30,买入,无效,无效,2019年12月2日
200,5,7,sell,NULL,NULL,2019年3月12日
200,6,50,转出,空,100,1/2/2020


我的报告输出需要显示与单位余额相关的存货相关的账户的完整详细信息

报告输出:
[级别]、账户、trxid、父trxid、已交易单位、交易类型、转帐人、转帐人、日期、单位余额
0、100、1、空、100、买、空、空、1/1/2020、100
0、100、2、空、50、转入、200、空、1/2/2020、空
1200,3,2,40,买入,无效,无效,2019年1月12日,33
1200,4,2,30,买入,无效,无效,2019年12月2日,17
1200,5,2,7,出售,无效,无效,2019年3月12日,0
1200,6,2,50,转出,空,100,1/2/2020,0

*先进先出逻辑将售出的7个单元应用到第一次购买的账户200。然后转出应计算剩余合格交易的单位余额

我今天使用的SQL代码仅在转出全部库存金额时有效,而不是部分转出:

    select
        [level],
        parentid,
        trxid,
        account,
        transactiontype,
        date,
        rnk,
        transacted_units,
        cumulative,
        CASE 
            WHEN cumulative>0 and transacted_units>=cumulative THEN cumulative
            WHEN cumulative>0 and transacted_units<cumulative THEN transacted_units 
            ELSE 0 
        END units_bal
    from (
        select
            *, 
            sum(transacted_units*Positive_Negative_Indicator) over (partition by parenttrxid, account order by rnk, date, trxid RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) cumulative
        from (

            select *,       
                CASE 
                    WHEN transacted_units*Positive_Negative_Indicator < 0 THEN 0 
                    ELSE ROW_NUMBER() OVER (PARTITION BY parenttrxid, account ORDER BY Positive_Negative_Indicator ASC, date ASC, trxid ASC) 
                END rnk
            from Transactions

        ) a
    ) a
选择
[级别],
父ID,
trxid,
账户
交易类型,
日期,
rnk,
交易单位,
累计的
案例
当累积>0且交易单位>时=累积然后累积
当每个当前“in”交易的累积>0且交易单位时,计算之前“in”交易的运行总数(单位)。然后分配前一个“入”事务未消耗的尽可能多的“出”单位(尽可能多的“出”单位==当前“入”事务可消耗的“出”单位的运行总数)

declare@t表
(
帐户int,
trxid int,
trunits int,
trtype varchar(20),
转换成整数,
转换为整数,
日期
);
插入@t(账户、trxid、trunits、trtype、transfrom、transto、日期)
价值观
(100,1100,'buy',NULL,NULL,'20200101'),
(100,2,50,“转入”,200,空,“20200201”),
(200,3,40,'buy',NULL,NULL,'20190112'),
(200,4,30,'buy',NULL,NULL,'20190213'),
(200,5,10,'buy',NULL,NULL,'20190214'),
(200,6,7,'sell',NULL,NULL,'20190315'),
(200,7,9,'sell',NULL,NULL,'20190316'),
(200,8,25,'buy',NULL,NULL,'20190317'),
(200,9,39,'sell',NULL,NULL,'20190318'),
(200,10,18,'sell',NULL,NULL,'20190319'),
(200,11,14,'sell',NULL,NULL,'20190320'),
(200,11,50,“转出”,空,100,“20200201”);
选择*,如果t.trtype不在('sell','transfer out'),则选择t.trunits-isnull(otu.out\u单位,0),否则null结束为剩余的\u单位
从…起
(
选择*,求和(trtype不在('sell','transfer out')时的情况,然后trunits else 0 end)超过(按帐户顺序划分,按无界前一行和前一行之间的日期行)作为上一个运行单位
来自@t
)as t
外敷
(
选择top(1)ort.out\u units\u running\u total-isnull(t.previous\u in\u running\u units,0)作为out\u单元
从…起
(
选择超过(按日期排序)的总和(o.trunits)作为out\U units\U running\U total
从@t到o
其中o.tr输入('sell','transfer out')
和o.账户=t.账户
和t.trtype not in('sell','transfer out')——交叉申请“out”交易时无需计算
)as ort——超出运行总数
其中,ort.out\U units\U running\U total-isnull(t.PREVICE\U in\U running\U units,0)对于每个当前“in”事务,计算前一个“in”事务的运行总数(单位)。然后分配前一个“in”事务未消耗的尽可能多的“out”单位(尽可能多的“out”单位==运行的“out”总数)当前“in”事务可以使用的单位)

declare@t表
(
帐户int,
trxid int,
trunits int,
trtype varchar(20),
转换成整数,
转换为整数,
日期
);
插入@t(账户、trxid、trunits、trtype、transfrom、transto、日期)
价值观
(100,1100,'buy',NULL,NULL,'20200101'),
(100,2,50,“转入”,200,空,“20200201”),
(200,3,40,'buy',NULL,NULL,'20190112'),
(200,4,30,'buy',NULL,NULL,'20190213'),
(200,5,10,'buy',NULL,NULL,'20190214'),
(200,6,7,'sell',NULL,NULL,'20190315'),
(200,7,9,'sell',NULL,NULL,'20190316'),
(200,8,25,'buy',NULL,NULL,'20190317'),
(200,9,39,'sell',NULL,NULL,'20190318'),
(200,10,18,'sell',NULL,NULL,'20190319'),
(200,11,14,'sell',NULL,NULL,'20190320'),
(200,11,50,“转出”,空,100,“20200201”);
选择*,如果t.trtype不在('sell','transfer out'),则选择t.trunits-isnull(otu.out\u单位,0),否则null结束为剩余的\u单位
从…起
(
选择*,求和(trtype不在('sell','transfer out')时的情况,然后trunits else 0 end)超过(按帐户顺序划分,按无界前一行和前一行之间的日期行)作为上一个运行单位
来自@t
)as t
外敷
(
选择top(1)ort.out\u units\u running\u total-isnull(t.previous\u in\u running\u units,0)作为out\u单元
从…起
(
在(按日期排序)上选择总和(o.trunits)
declare @t table
(
    Account int, 
    trxid int,
    trunits int,
    trtype varchar(20),
    transfrom int,
    transto int,
    thedate date
);

insert into @t(Account, trxid, trunits, trtype, transfrom, transto, thedate)
values
(100, 1, 100, 'buy', NULL, NULL, '20200101'),
(100, 2, 50, 'transfer in', 200, NULL, '20200201'),
(200, 3, 40, 'buy', NULL, NULL, '20190112'),
(200, 4, 30, 'buy', NULL, NULL, '20190213'),
(200, 5, 10, 'buy', NULL, NULL, '20190214'),
(200, 6, 7, 'sell', NULL, NULL, '20190315'),
(200, 7, 9, 'sell', NULL, NULL, '20190316'),
(200, 8, 25, 'buy', NULL, NULL, '20190317'),
(200, 9, 39, 'sell', NULL, NULL, '20190318'),
(200, 10, 18, 'sell', NULL, NULL, '20190319'),
(200, 11, 14, 'sell', NULL, NULL, '20190320'),
(200, 11, 50, 'transfer out', NULL, 100, '20200201');



select *, case when t.trtype not in ('sell', 'transfer out') then t.trunits -isnull(otu.out_units, 0) else null end as leftover_units
from 
(
select *, sum(case when trtype not in ('sell', 'transfer out') then trunits else 0 end) over (partition by Account order by thedate rows between unbounded preceding and 1 preceding) as previous_in_running_units
from @t
) as t
outer apply
(
    select top (1) ort.out_units_running_total - isnull(t.previous_in_running_units, 0) as out_units
    from
    (
        select sum(o.trunits) over(order by o.thedate) as out_units_running_total
        from @t as o
        where o.trtype in ('sell', 'transfer out')
        and o.Account = t.Account
        and t.trtype not in ('sell', 'transfer out') --no calculations needed when cross applying for "out" transactions
    ) as ort --out running totals
    where ort.out_units_running_total-isnull(t.previous_in_running_units, 0) <= t.trunits --<-- ("in") use as many out units as can be consumed by current t.transaction/date after deducting what has been consumed by the previous t.transaction/date
    and ort.out_units_running_total-isnull(t.previous_in_running_units, 0) > 0 --not needed(?) if balance is guaranteed.. total_out = total_in 
    order by ort.out_units_running_total desc 
) as otu; --"out units"