3

データベースに少量のロジックを含むビューを作成したいと考えています。商品の在庫確認のためです。SQL Fiddleとして単純化されたスキーマを作成しました。

ただし、複数の列で値を再利用する必要があります。これが私がやりたいことです:

SELECT
    product.id AS id,
    SUM(IFNULL(purchase_product.amount,0)) AS amountSold,
    IFNULL(product.amountAvailable-amountSold,~0) AS amountAvailable,
    amountAvailable>0 AS isAvailable,
FROM product
    LEFT JOIN purchase_product ON purchase_product.product_id = product.id
    LEFT JOIN purchase ON purchase.id = purchase_product.purchase_id AND purchase.completed = TRUE
GROUP BY product.id

しかし、「amountSold」と「mountAvailable」を再利用できないため、これは失敗します。これにより、計算を繰り返すか、サブクエリを使用するか (/SELECT に結合する/より多くのビューを使用する) のいずれかを選択できます。

これは、私が思いついた最も合理的な妥協案であり、Fiddle にあります。もっと優雅な解決策はありますか?

4

2 に答える 2

2

私はあなたの現在のソリューションがとても好きです。実際の問題はありませんが、これは少し簡単かもしれません:

SELECT  Product.ID, 
        COALESCE(AmountSold, 0) AS AmountSold,
        GREATEST(COALESCE(AmountAvailable, ~0) - COALESCE(AmountSold, 0), 0) AS AmountAvailable,
        COALESCE(AmountAvailable, ~0) - COALESCE(AmountSold, 0) > 0 AS IsAvailable
FROM    Product
        LEFT JOIN 
        (   SELECT  Product_ID, SUM(Amount) AS AmountSold
            FROM    Purchase_Product
                    INNER JOIN Purchase
                        ON Purchase.ID = Purchase_ID
            WHERE   Completed = 1
            GROUP BY Product_ID
        ) sold
            ON Sold.Product_ID = Product.ID;

唯一の実際の変更点は、テーブル スキャンの回数を減らすためにサブクエリの product への参照を削除し、計算のロジックを少し変更したことです。

最後にGREATEST、データの整合性の問題を考慮して、否定的な製品が利用できないようにするために、そこに追加しました.

さらにサブクエリを実行してクエリを読みやすくすることもできますが、ほとんどの場合、パフォーマンスは向上しません。

SQL Fiddleは、わずかに改善された実行計画を示しています。

于 2012-06-01T20:31:42.537 に答える
1

結合を使用してサブクエリで実行できます。

select product.id, s.amountsold,
       IFNULL(product.amountAvailable-s.amountSold,~0) AS amountAvailable, 
       product.amountAvailable>0 AS isAvailable
       -- although you probably mean
       -- IFNULL(product.amountAvailable-s.amountSold,~0) > 0 as isAvailable
from product join
     (SELECT product.id AS id, 
             SUM(IFNULL(purchase_product.amount,0)) AS amountSold,
             IFNULL(product.amountAvailable-amountSold,~0) AS amountAvailable, 
             amountAvailable>0 AS isAvailable
      FROM product LEFT JOIN
            purchase_product
            ON purchase_product.product_id = product.id LEFT JOIN
            purchase
            ON purchase.id = purchase_product.purchase_id AND
               purchase.completed = TRUE
      GROUP BY product.id
    ) t
    on product.id = t.id

他のデータベースでは、Windows 関数を使用して同様のことを行うことができます。ただし、mysql はそれらをサポートしていません。

また、isAvailable は、sold を差し引いた後にしたいと思うので、提案として追加しました。

于 2012-06-01T19:55:36.817 に答える