2013-01-31 17 views
10

は、私はいくつかの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のマージンは17.50と売れ残り左の15.00で購入1で購入した2と

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

です。

+0

1つのテーブルが購入または卸売価格であり、もう1つは小売売上データですか?だからあなたは '$ 17.50/3'の' 5/1'に積極的な卸売価格を設定していますか?次に、現時点でのアクティブプライス*を、アクティブ期間の小売売上データと比較したいとしますか? – Yuck

+0

また、使用しているRDBMS製品を知るのに役立ちます。このような問題は、確かにベンダー固有のSQL機能(CTE、パーティショニングなど)から恩恵を受けることになります。 – Yuck

+0

@Yuck、正しい、これは卸売りの購入データと小売売上データです。このデータはSQL ServerとMySQLの両方にありますが、可能であれば一般的なSQLソリューションが最適です。 –

答えて

5

良い質問です。私が取っているアプローチは、総売上高を計算することです。そして、累積購入を計算し、組み合わせのために右算術取得するために特別なロジックと組み合わせる:

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 

注:それは構文エラーがあるかもしれないので、私はこのクエリをテストしていません。

+0

はじめに、mysqlには完全な外部結合がありません。 'union'はこれを回避する一つの方法です。 –

+0

@ebyrob。 。 。撮影ポイント。完全な外部結合は必要ないので、簡単な内部結合に切り替えました。私はスカスがないことを心配していたからです。 –

+0

私は欲しいものを得るためにcase文を修正しなければならなかったが、これはうまくいくようだ。 http://sqlfiddle.com/#!2/b6177/20/0 –

0

の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例えば

sku margin 
    123 45,75 
    456 20,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) 

を設定...

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

+0

ty Yuck ..私は問題を誤解していました...私は答えを変更しました... – Frederic

-1

これはOracleのクエリですが、どのSQLでも動作します。これは単純化されており、必要な計算はすべて含まれていません。自分で追加することができます。あなたは* 1ない17.50 * 3 17.50として少し差分の合計が表示されます。

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) 
+0

彼らは先入れ先出し方式で販売された在庫に対して余裕を持ち、残りの在庫を知りたがっています。残りの在庫がマージンの結果に反映されることを望んでおらず、残っている在庫とそれらの特定のユニットに支払った金額を知りたがっています。 –

+0

@ Love2Learn - そして?なぜ私はすべてのことを計算するために私の頭を壊すだろう...?私は計算を行う簡単な方法を示しました。ユーザーに数学をさせてください。シーケンスは何ですか?それはポストで言及されていませんでした。私が見たのは、私が従った数式でした。ゴードンは素晴らしいです、私は本当にそうだと思いますが、それを読むことさえできますか?なぜ複雑になるのですか? – Art

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; 
関連する問題