13

假设我有一些 SKU 的采购和销售数据:

po_id | sku | purchase_date    | price | qty
----------------------------------------------
    1 | 123 | 2013-01-01 12:25 | 20.15 |   5
    2 | 123 | 2013-05-01 15:45 | 17.50 |   3
    3 | 123 | 2013-05-02 12:00 | 15.00 |   1
    4 | 456 | 2013-06-10 16:00 | 60.00 |   7

sale_id | sku | sale_date        | price | qty
------------------------------------------------
      1 | 123 | 2013-01-15 11:00 | 30.00 |   1
      2 | 123 | 2013-01-20 14:00 | 28.00 |   3
      3 | 123 | 2013-05-10 15:00 | 25.00 |   2
      4 | 456 | 2013-06-11 12:00 | 80.00 |   1

假设它们按照购买顺序出售,我如何通过 SQL 找到销售利润?例如,sku 123 的边距是

30*1 + 28*3 + 25*2 - 20.15*5 - 17.50*1

17.50 购买了 2 个,15.00 购买了 1 个未售出。

4

4 回答 4

7

好问题。我采用的方法是计算总销售额。然后计算累积购买量,并将它们与特殊逻辑结合起来,得到组合的正确算法:

select s.sku,
       (MarginPos - SUM(case when s.totalqty < p.cumeqty - p.qty then p.price * p.qty
                             when s.totalqty between p.cumeqty - p.qty and p.qty
                             then s.price * (s.totalqty - (p.cumeqty - p.qty))
                             else 0
                        end)
       ) as Margin
from (select s.sku, SUM(price*qty) as MarginPos, SUM(qty) as totalqty
      from sales s
     ) s left outer join
     (select p.*,
             (select SUM(p.qty) from purchase p2 where p2.sku = p.sku and p2.sale_id <= p.sale_id
             ) as cumeqty
      from purchase s
     )
     on s.sku = p.sku
group by s.sku, MarginPos

注意:我没有测试过这个查询,所以它可能有语法错误。

于 2013-01-31T19:53:04.553 回答
1

设置环境

    declare @purchased table (id int,sku int,dt date,price money,qty int)
    declare @sold table (id int,sku int,dt date,price money,qty int)

    insert into @purchased
    values( 1 , 123 , '2013-01-01 12:25' , 20.15 ,   5)
        ,(2 , 123 , '2013-05-01 15:45' , 17.50 ,   3)
        ,(3 , 123 , '2013-05-02 12:00' , 15.00 ,   1)
        ,(4 , 456 , '2013-06-10 16:00' , 60.00 ,   7)

    insert into @sold
    values(1 , 123 , '2013-01-15 11:00' , 30.00 ,   1)
          ,(2 , 123 , '2013-01-20 14:00' , 28.00 ,   3)
          ,(3 , 123 , '2013-05-10 15:00' , 25.00 ,   2)
          ,(4 , 456 , '2013-06-11 12:00' , 80.00 ,   1)

一个sqlserver解决方案应该是......

    with cte_sold as (select sku,sum(qty) as qty, SUM(qty*price) as total_value
                      from @sold
                      group by sku
                      )
    ,cte_purchased as (select id,sku,price,qty 
                       from @purchased
                       union all select id,sku,price,qty-1 as qty 
                       from cte_purchased
                       where qty>1
                    )
    ,cte_purchased_ordened as(select ROW_NUMBER() over (partition by sku order by id,qty) as buy_order
                                    ,sku
                                    ,price
                                    ,1 as qty
                              from cte_purchased 
    )

    select P.sku
          ,S.total_value - SUM(case when P.buy_order <= S.qty then P.price else 0 end) as margin
    from cte_purchased_ordened P
    left outer join cte_sold S
    on S.sku = P.sku
    group by P.sku,S.total_value,S.qty

取得的成果

    sku margin
    123 45,75
    456 20,00

问题描述中 sku 123 示例的相同结果...

30*1 + 28*3 + 25*2 - 20.15*5 - 17.50*1 = 45.75

于 2013-01-31T19:45:45.357 回答
0

这真的很可怕,因为它会更改查询中的 MySQL 变量,但它确实有效(并且需要 3 个语句):

select
  @income := sum(price*qty) as income,
  @num_bought := cast(sum(qty) as unsigned) as units
from sale
where sku = 123
;

select
  @expense := sum(expense) as expense,
  sum(units) as units
from (select
  price * least(@num_bought, qty) as expense,
  least(@num_bought, qty) as units,
  @num_bought := @num_bought - least(@num_bought, qty)
from purchase
where sku = 123 and @num_bought > 0
order by po_id
) as a
;

select round(@income - @expense, 2) as profit_margin;
于 2013-01-31T22:27:04.873 回答
-1

这是 Oracle 查询,但应该适用于任何 SQL。它是简化的,不包括所有必要的计算。您可以自己添加它们。您会看到总数略有不同,为 17.50*3 而不是 17.50*1:

SELECT po_sku AS sku, po_total, sale_total, (po_total-sale_total) Margin
  FROM
 (
  SELECT SUM(price*qty) po_total, sku po_sku
    FROM stack_test
  GROUP BY sku
 ) a,
 (
  SELECT SUM(price*qty) sale_total, sku sale_sku
    FROM stack_test_sale
   GROUP BY sku
 ) b
 WHERE po_sku = sale_sku
 /

SKU     PO_TOTAL    SALE_TOTAL  MARGIN
---------------------------------------------------
123     168.25      164         4.25
456     420         80          340

如果需要,您还可以按 SKU 添加分区:

SUM(price*qty) OVER (PARTITION BY sku ORDER BY sku)
于 2013-01-31T21:36:48.073 回答