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”和“amountAvailable”。这让我可以选择是重复计算还是使用子查询(/加入 SELECT 的/使用更多视图)。

这是我能想到的最合理的妥协是在小提琴中。有没有更优雅的解决方案?

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;

唯一真正的变化是我在子查询中删除了对产品的引用以减少表扫描的次数,并且还稍微改变了计算的逻辑。

最后我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 在您减去已售出的商品后出现,因此我将其添加为建议。

于 2012-06-01T19:55:36.817 回答