SQL 服务器价格 table 加权购买价格

SQL Server price table weighted to buying price

我有 3 个 table:

买入

ID Item qty price
1 1001 10 1.00
2 1001 10 2.00
3 1001 10 3.00
4 1002 10 2.00
5 1002 10 1.00
6 1003 10 1.00
7 1004 10 1.00
8 1004 10 2.00

回退

Item price
1001 3.00
1002 3.00
1003 4.00

股票

Item stock
1001 15
1002 5
1003 25
1004 15

我必须计算每件商品的实际价格。为此,我必须从最大 ID 到最小 ID 检查每行 table“购买”,并在库存充足的情况下获取所有价格。如果在table买的不够多,我就得用部分股票的后备价格,我先没有价格在table.

因此对于项目编号。 1001,库存为 15。在 ID 3 中找到 10 件的价格(3.00 美元);行 ID 2 中剩余 5 件的价格(2.00 美元)。所以正确的实际股价是 2.66 美元。

商品编号1002,库存为 5。行 ID 5 中的最新购买价格为 1.00 美元,数量超过 5。因此正确的实际库存价格为 1.00 美元。

商品编号1003,库存为 25。ID 6 行中只有一个条目,10 个,每个 1.00 美元。所以缺少 15 件的价格必须从后备 table 4.00 美元中扣除。所以正确的实际股价是 2.80 美元。

结果应该是这样的:

Item stock value
1001 15 2.66
1002 5 1.00
1003 25 2.80

但我不知道它是如何工作的。非常感谢您的帮助。

您需要创建 Buys 中数量的 运行 总和,并以此为基础计算价格。

这有点复杂,因为 Buys 中的行数可能太多或不够,无法完成库存。

SELECT
  s.Item,
  s.stock,
  (
    ISNULL(b.FoundStockPrice, 0)
    + CASE WHEN s.stock > ISNULL(b.FoundStock, 0)
           THEN s.stock - ISNULL(b.FoundStock, 0)
           ELSE 0 END * f.price
  ) / s.stock
FROM Stock s
JOIN Fallback f ON f.Item = s.Item
OUTER APPLY (
    SELECT
      FoundStock = SUM(b.qty),
      FoundStockPrice = SUM(
        CASE WHEN b.FullStock > b.RunningSum THEN b.qty
          ELSE b.FullStock - (b.RunningSum - b.qty) END
        * b.price)
    FROM (
        SELECT *,
          RunningSum = SUM(b.qty) OVER (PARTITION BY b.Item
                         ORDER BY b.ID DESC ROWS UNBOUNDED PRECEDING),
          FullStock = s.stock
        FROM Buys b
        WHERE b.Item = s.Item
    ) b
    WHERE b.RunningSum - b.qty < s.stock
) b;

步骤如下:

  • 对于每个 Stock 取所有相关的 Buys 行。
  • 计算 qty 的 运行 总和,然后过滤到 运行 总和 包含 最终 [=16] 的行=](换句话说它必须达到之前的运行和)。
  • 将这些 Buys 行乘以它们的 price,考虑到我们需要扣除任何超过必要的 stock。也取数量的总和。
  • 最终价格是:之前计算的总价,加上任何剩余未找到的stock乘以fallback.price,再除以总价stock

db<>fiddle

比较股票时使用条件聚合来购买运行总计,最后应用后备

select t.item, (s + t.qf * f.price) s, stock, (s + t.qf * f.price) / stock  price
from (
  select s.Item, s.Stock, 
     sum(coalesce(case when b.qe <= Stock then b.qty else Stock - b.qs end * b.price, 0)) s,
     --  qty for fallback
     min(case when Stock > coalesce(b.qe,0) then Stock - coalesce(b.qe,0) else 0 end) qf
  from Stock s
  left join (
      select Item, qty, price, ID,
        sum(qty) over(partition by Item order by ID desc) - qty qs, -- starting runnig total
        sum(qty) over(partition by Item order by ID desc) qe  -- ending runnig total
      from Buys
    ) b on s.Item = b.Item and s.Stock > b.qs
  group by s.Item, s.Stock
) t
join Fallback f on f.Item = t.Item;
order by t.Item;

如果某个项目可能缺少后备,则需要进行细微调整。

select t.item, (s + t.qf * coalesce(f.price, 0)) s, stock, (s + t.qf * coalesce(f.price, 0)) / stock  price
from (
  select s.Item, s.Stock, 
     sum(coalesce(case when b.qe <= Stock then b.qty else Stock - b.qs end * b.price, 0)) s,
     --  qty for fallback
     min(case when Stock > coalesce(b.qe,0) then Stock - coalesce(b.qe,0) else 0 end) qf
  from Stock s
  left join (
      select Item, qty, price, ID,
        sum(qty) over(partition by Item order by ID desc) - qty qs, -- starting runnig total
        sum(qty) over(partition by Item order by ID desc) qe  -- ending runnig total
      from Buys
    ) b on s.Item = b.Item and s.Stock > b.qs
  group by s.Item, s.Stock
) t
left join Fallback f on f.Item = t.Item
where t.qf = 0 or f.item is not null
order by t.Item;

如果需要回退但缺少回退,则查询将不会 return 一行。否则该行是 returned.

db<>fiddle