微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

T-SQL,仓库原理,两个数据集使用FIFO

如何解决T-SQL,仓库原理,两个数据集使用FIFO

我想使用 FIFO 合并两个数据集之间的数据。我认为仓库原理是一个很好的例子来解释我需要什么。

购买表:

ID_BUY 日期 项目 计数
39 2022-01-01 00:00 铅笔 1000
41 2022-02-02 00:00 铅笔 2000
44 2022-03-03 10:00 铅笔 3000
45 2022-03-03 12:00 铅笔 3500
47 2022-04-04 00:00 铅笔 4000
51 2022-05-05 00:00 胶水 5000
53 2022-06-06 00:00 6000

卖出表:

ID_SELL 日期 项目 计数
40 2022-01-01 16:00 铅笔 1000
42 2022-02-02 17:00 铅笔 1200
43 2022-02-02 18:00 铅笔 800
46 2022-03-03 14:00 铅笔 6500
48 2022-04-04 15:00 铅笔 2100
49 2022-04-04 16:00 铅笔 1100
52 2022-05-05 20:00 胶水 2000

预期数据:

ID ID_BUY ID_SELL 计数
1 39 40 1000
2 41 42 1200
3 41 43 800
4 44 46 3000
5 45 46 3500
6 47 48 2100
7 47 49 1100
8 51 52 2000

预期数据描述:

  • Row ID = 1 --> 2022-01-01 我买了 1000 支铅笔,几个小时后卖出了 1000 支铅笔。
  • 行 ID = 2 和 3 --> 2022-02-02 我购买了 2000 支铅笔,并向客户编号 1 (ID = 2) 出售了 1200 支铅笔,向客户编号 2 (ID = 3) 出售了 800 支铅笔。
  • 行 ID = 4 和 5 --> 2022-03-03 我在两次交易(3000 和 3500)中购买了 6500 支铅笔,并在一次交易中卖出了它们(6500)。在这种情况下,行中的限制由购买交易决定。
  • 行 ID = 6 和 7 --> 2022-04-04 我在两次交易 (2100 + 1100) 中买了 4000 支铅笔并卖出了 3200 支。现在我有 800 支铅笔 (4000 - 3200 = 800) 等待下一笔交易。在这种情况下,行中的限制由卖出交易决定。
  • 预期数据中没有图书,因为它们没有售出。

我尝试使用基于“销售表”的游标来解决此问题。当我这样做时,我注意到我必须在游标内使用游标。第二个游标必须基于“BUY 表”加上未从预期数据表结算的内容,在接下来的步骤中,我将不得不使用 IF。也许有更简单的方法解决这个问题? CTE?

解决方法

合并买卖数据并计算累计“存货数量”:

if object_id('tempdb..#tmp_fifo_count') is not null drop table #tmp_fifo_count
select
   b.ID_BUY,s.ID_SELL,(b.BuyedCummulativeCount - s.SoldCummulativeCount) as CountInStock,row_number() over(partition by b.ID_BUY order by s.[Date] asc) as RN,-- flag first sold over limit
   case
      when (b.BuyedCummulativeCount - s.SoldCummulativeCount) < 0 and b.BuyedCummulativeCount >= s.[Count]
        then (b.BuyedCummulativeCount - s.SoldCummulativeCount) -- correction to case over limit (for n:m relationship)
      else 0
   end +
   case
      when b.[Count] >= s.[Count] then s.[Count]    -- i have more in stock then i sold
      else b.[Count]                                -- i cannot sell over limit
   end as [Count]
into #tmp_fifo_count
from (
   select *,(select sum([Count]) from #tmp_buy b2 where b2.[Date] <= b0.[Date]) as BuyedCummulativeCount
   from #tmp_buy b0) as b
left join (
   select *,(select sum([Count]) from #tmp_sell s2 where s2.[Date] <= s0.[Date]) as SoldCummulativeCount
   from #tmp_sell s0) as s
on b.[Date] <= s.[Date]

获取结果:

-- output
select
   row_number() over(order by ID_BUY,ID_SELL) as ID,ID_BUY,ID_SELL,[Count] 
   --case when CountInStock >= 0 then CountInStock else 0 end as CountInStock
from #tmp_fifo_count
where (CountInStock >= 0 or RN = 1) -- Fully covered by one buy or not Fully covered by one buy
   and ID_SELL is not null          -- they were sold

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。