2017-10-01 10 views
1

私は、PHPとMySQLベースのシステムを使用して、レストランの製品と経費を整理しています。複数のテーブルのデータを使用して最新の平均価格を計算するMySQLクエリ

私は4つのテーブルにデータを編成しています。

アイテムテーブル

id | name 
1 | Beer 
2 | Vodka 

製品テーブル

id | item_id | name 
1 | 1 | Budweiser 
2 | 1 | Sam Adams 
3 | 2 | Smirnoff 
4 | 2 | Grey Goose 

サプライヤーテーブル

id | name 
1 | Supplier 1 
2 | Supplier 2 

費テーブル

id | product_id | cost | quantity | supplier | date 
1 |  1  | 2.99 |  1 |  1 | 2017-09-05 
2 |  1  | 3.00 |  2 |  2 | 2017-09-10 
3 |  1  | 2.50 |  1 |  1 | 2017-09-20 
4 |  1  | 3.98 |  2 |  1 | 2017-09-22 
5 |  1  | 4.00 |  1 |  2 | 2017-09-25 
6 |  1  | 8.00 |  2 |  2 | 2017-09-27 

経費表(日付に基づく)の最新の3つの項目の平均費用(費用/数量)に基づいて特定の製品の最も安いサプライヤを把握できるMYSQLクエリを書きたいと思います。 2.99、2.50および1.99: - 単位あたりのコスト

サプライヤー1つの最後の3つのエントリ:

は、ここで私は計算したいものです。平均= 2.49

サプライヤ2最後の3つのエントリ - 単位あたりのコスト:1.50,4.00,4.00。 Average = 3.16

SQLは、サプライヤ1がProduct 1(Budweiser)にとって最も安いオプションであると返すべきです。

これまでのところ、私はこれを試みたが、私は少し失われ、混乱しています:

select * from products 
INNER JOIN expenses 
ON products.id = expenses.product 
AND products.item = '1' 
ORDER BY (expenses.cost/expenses.quantity) 
LIMIT 3; 

このクエリの出力は、私は:(を把握しようとしているものとは長い道のりであるです:

id | item_id | name | id | product_id | cost | quantity | supplier | date 
1 | 1 |Budweiser| 2 |  1  | 3.00 | 2  | 2  | 2017-09-10 
1 | 1 |Budweiser| 4 |  1  | 3.98 | 2  | 1  | 2017-09-22 
1 | 1 |Budweiser| 3 |  1  | 2.50 | 1  | 1  | 2017-09-20 

私はサンプルデータに基づいて探しています出力は次のようになります。

cheapest_supplier 
     1 
+0

は、我々はこの仕事での試みを見ることはできますか?あなたの最初のことは、 'ORDER BY 'と' LIMIT 3'の 'Supplier'と' Expenses'の間のジョイントのように見えます。 2番目の同様のクエリを実行することによって平均を行うことはできますが、平均関数を使用します(マニュアルに記載されています)。 – halfer

+0

ありがとう、@halferこれは私が持っている限りです。製品から code'select *が INNERはON経費を登録しようproducts.id = expenses.product AND products.item = '1'(expenses.cost/expenses.quantity) LIMIT 3 BY ORDER; ' –

+0

すべての経費IDSなぜですか? – Strawberry

答えて

4

私は経費テーブルの最新3つのentiresの 項目(コスト/数量)あたりの平均コストに基づいて、特定の製品の最も安い業者を把握することができMYSQLクエリを書きたいです (日付に基づく)

これは、日付に基づいてランキングを生成するためにユーザー変数で動作するクエリを必要とします。 最後の3つの日付のみを選択してください。

クエリ

SELECT 
* 
FROM (
    SELECT 
    * 
    , CASE 
     WHEN @supplier = supplier 
     THEN @rank := @rank + 1 
     ELSE @rank := 1 
    END 
     AS rank 
    , @supplier := supplier 
    FROM 
    Expenses 
    CROSS JOIN (
    SELECT 
     @supplier := NULL 
    , @rank := 0 
    ) 
    AS 
     init_user_params 
    WHERE 
     product_id = 1  
    ORDER BY 
     supplier ASC 
    , DATE DESC 
) 
AS Expenses_ranked 
WHERE 
    Expenses_ranked.rank <= 3 

結果結果はサプライヤーごとの平均のリストを生成することを使用し

id product_id cost quantity supplier date  @supplier := NULL @rank := 0 rank @supplier := supplier 
------ ---------- ------ -------- -------- ---------- ----------------- ---------- ------ ----------------------- 
    4   1 3.98   2   1 2017-09-22 (NULL)      0  1      1 
    3   1 2.50   1   1 2017-09-20 (NULL)      0  2      1 
    1   1 2.99   1   1 2017-09-05 (NULL)      0  3      1 
    6   1 8.00   2   2 2017-09-27 (NULL)      0  1      2 
    5   1 4.00   1   2 2017-09-25 (NULL)      0  2      2 
    2   1 3.00   2   2 2017-09-10 (NULL)      0  3      2 

クエリ

SELECT 
    Expenses_ranked.supplier 
, AVG(Expenses_ranked.cost/Expenses_ranked.quantity) AS AVG 
FROM ( 

    SELECT 
    * 
    , CASE 
     WHEN @supplier = supplier 
     THEN @rank := @rank + 1 
     ELSE @rank := 1 
    END 
     AS rank 
    , @supplier := supplier 
    FROM 
    Expenses 
    CROSS JOIN (
    SELECT 
     @supplier := NULL 
    , @rank := 0 
    ) 
    AS 
     init_user_params 
    WHERE 
     product_id = 1  
    ORDER BY 
     supplier ASC 
    , DATE DESC 
) 
AS Expenses_ranked 
WHERE 
    Expenses_ranked.rank <= 3 
GROUP BY 
    Expenses_ranked.supplier 

結果

supplier avg   
-------- -------------- 
     1 2.4933333333 
     2 3.1666666667 

今、私たちは、最も安いサプライヤーに

クエリを取得するには、単純なORDER BY [] ASC LIMIT 1を使用することができます

SELECT 
Expenses_ranked_avg.supplier AS cheapest_supplier 
FROM ( 

    SELECT 
    Expenses_ranked.supplier 
    , AVG(Expenses_ranked.cost/Expenses_ranked.quantity) AS AVG 
    FROM ( 

    SELECT 
    * 
    , CASE 
     WHEN @supplier = supplier 
     THEN @rank := @rank + 1 
     ELSE @rank := 1 
     END 
     AS rank 
    , @supplier := supplier 
    FROM 
    Expenses 
    CROSS JOIN (
    SELECT 
     @supplier := NULL 
    , @rank := 0 
    ) 
    AS 
     init_user_params 
    WHERE 
     product_id = 1  
    ORDER BY 
     supplier ASC 
    , DATE DESC 
    ) 
     AS 
     Expenses_ranked 
    WHERE 
     Expenses_ranked.rank <= 3 
    GROUP BY 
     Expenses_ranked.supplier 
) 
    AS Expenses_ranked_avg 
ORDER BY 
Expenses_ranked_avg.avg ASC 
LIMIT 1 

結果

cheapest_supplier 
------------------- 
        1 

より最適なクエリ。

where変数内でユーザー変数を宣言することも可能です。 ランキングを除外することを直接可能にします。

id product_id cost quantity supplier date   
------ ---------- ------ -------- -------- ------------ 
    1   1 2.99   1   1 2017-09-05 
    3   1 2.50   1   1 2017-09-20 
    4   1 3.98   2   1 2017-09-22 
    2   1 3.00   2   2 2017-09-10 
    5   1 4.00   1   2 2017-09-25 
    6   1 8.00   2   2 2017-09-27 

クエリ

SELECT 
    * 
    FROM 
    Expenses 
    WHERE 
    (
    CASE 
     WHEN @supplier = supplier 
     THEN @rank := @rank + 1 
     ELSE @rank := 1 
    END 
    ) 
AND 
    (@supplier := supplier) 
AND 
    @rank <= 3 
AND 
    product_id = 1 
ORDER BY 
    supplier ASC 
, DATE ASC 

結果は、今では使用安い業者を見つけるために、この結果セットは簡単です。

クエリ

SELECT 
    Expenses_ranked.supplier AS cheapest_supplier 
FROM ( 

    SELECT 
    * 
    FROM 
    Expenses 
    WHERE 
    (
    CASE 
     WHEN @supplier = supplier 
     THEN @rank := @rank + 1 
     ELSE @rank := 1 
    END 
    ) IS NOT NULL 
AND 
    (@supplier := supplier) IS NOT NULL 
AND 
    @rank <= 3 
AND 
    product_id = 1 
ORDER BY 
    supplier ASC 
, DATE ASC 
) 
AS Expenses_ranked 
GROUP BY 
    Expenses_ranked.supplier 
ORDER BY 
    AVG(Expenses_ranked.cost/Expenses_ranked.quantity) ASC 
LIMIT 1 

結果

cheapest_supplier 
------------------- 
        1 
+0

ありがとう、これは私が探していた結果を正確に生成しています。今私はちょうど私がそれから学ぶことができるようにコードの周りに私の頭をしようとする必要があります! –

+0

@Dingo Bruceなぜなら、私は複数の部分でクエリを分割したので、iamがやっていることを理解するのが簡単です。私が考える最も難しい部分は、ユーザー変数が使用されているランク付けです。 –

+0

レイモンド前に投稿したことはありませんでしたが、これは素晴らしい答えです。よくやった! – halfer

1

例:

SELECT x.product_id 
    , x.supplier_id 
    , x.date 
    , ROUND(AVG(y.cost/y.quantity),2) total_cost 
    FROM expenses x 
    JOIN expenses y 
    ON y.product_id = x.product_id 
    AND y.supplier_id = x.supplier_id 
    AND y.date <= x.date 
GROUP 
    BY product_id 
    , supplier_id 
    , date 
HAVING COUNT(*) = 3; 
+0

明確化を考えると、 'GROUP BY'は必要ありませんが、' y.cost/y.quantity ASC'で 'LIMIT 1'を使って並べ替えることができるので、一番安いのが一番上です。 – halfer

+0

このクエリの中の@Strawberryありがとうございます。どのproduct_idでクエリを実行するのですか?これは変数を挿入するためにwhileループの一部である必要があります。 –

+0

@halferそうです。私の理解は、計算は各サプライヤーによって提供された最後の3つの価格に基づいて行われたことに変わりはありません。 – Strawberry

関連する問題