Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 根据先进先出定价计算利润_Mysql_Sql_Sql Server - Fatal编程技术网

Mysql 根据先进先出定价计算利润

Mysql 根据先进先出定价计算利润,mysql,sql,sql-server,Mysql,Sql,Sql Server,假设我有一些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

假设我有一些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购买,未售出。

    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 123示例的结果相同


30*1+28*3+25*2-20.15*5-17.50*1=45.75这是个好问题。我采用的方法是计算总销售额。然后计算累计购买量,并将其与特殊逻辑相结合,以获得正确的组合算法:

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

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

这是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)

这真的很可怕,因为它在查询中更改了一个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;

你能澄清一下吗?一个表格是购买或批发价格,另一个是零售销售数据?那么,你将有效批发价定为17.50/3美元的5/1?然后,您想将当时的活动价格与活动期间的零售销售数据进行比较?这也有助于了解您正在使用的RDBMS产品。像这样的问题肯定会从特定于供应商的SQL功能中受益,例如CTE、分区等。@恶心,没错,这是批发购买数据和零售销售数据。我们在SQL Server和MySQL中都有这些数据,但是如果可能的话,一个通用的SQL解决方案将是最好的。这个解决方案将非常类似于先进先出的FIFO证券定价问题。你找过这样的东西吗?@不,有什么你能指给我的吗?他们想要按先进先出的顺序出售的存货的保证金,他们想要知道剩余的存货。他们不想在利润结果中考虑剩余的存货,他们想知道他们剩下的存货以及他们为这些特定的单位支付了多少。@Love2Learn-和?为什么我要打破我的头来计算所有这些。。。?我展示了做任何计算的简单方法。让用户做数学。顺序是什么?这篇文章没有提到。我看到的只是我遵循的一个公式。戈登很棒,我真的这么认为,但你能读懂吗?为什么过于复杂?首先,mysql没有完整的外部连接。联合是解决这个问题的一种方法。@ebyrob。我明白了。完全的外部连接甚至不需要,所以我将其切换为简单的内部连接。它就在那里,只是因为我担心丢失SKU。我不得不修改案例陈述以获得我想要的,但这似乎奏效了。注:费用总额可以简化为:SUMprice*GREATESTLEASTqty,totalqty-cumeqty-qty,0无需案例说明。
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;