说我有一些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
2在17.50购买,1在15.00购买,未售出。
答案 0 :(得分:6)
好问题。我采取的方法是计算总销售额。然后计算累积购买量,并将它们与特殊逻辑相结合,以获得组合的正确算术:
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
注意:我没有测试过此查询,因此可能会出现语法错误。
答案 1 :(得分:0)
设置环境
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
答案 2 :(得分: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;
答案 3 :(得分:-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)