LEFT OUTER JOIN的问题

时间:2013-12-04 22:48:18

标签: mysql join left-join outer-join right-join

我试图按销售量和日期获取产品清单。我还想显示尚未在列表中销售的产品,所以我尝试先做一个子查询,但是MYSQL给了我这样的信息:

操作数应包含1列

SELECT product.product_id, 
       product.product_brand_id, 
       product.product_model_id, 
       product.product_subcategory_id, 
       product.product_retail_price, 
       product.product_wholesale_price
FROM product
WHERE product.product_subcategory_id = $subcategory_id 
AND (SELECT SUM(product_sold.product_quantity) AS product_quantity_sold, 
            SUM(product_sold.product_total_price) AS total_price_sold 
     FROM product
     INNER JOIN product_sold 
        ON product.product_id = product_sold.product_id
     INNER JOIN sales 
        ON sales.sales_id = product_sold.product_sales_id 
     WHERE sales.sales_approved = '1' 
       AND sales.sales_approved_time > '$start_timestamp' 
       AND sales.sales_approved_time < '$end_timestamp')

子查询不起作用,所以我尝试使用LEFT OUTER JOIN按照其他成员的建议使用此查询:

SELECT product.product_id, 
       product.product_brand_id, 
       product.product_model_id, 
       product.product_subcategory_id, 
       product.product_retail_price, 
       product.product_wholesale_price, 
       SUM(product_sold.product_quantity) AS product_quantity_sold, 
       SUM(product_sold.product_total_price) AS total_price_sold 
FROM product
LEFT OUTER JOIN product_sold ON product.product_id = product_sold.product_id 
                            AND product.product_subcategory_id = $subcategory_id
LEFT OUTER JOIN sales ON sales.sales_id = product_sold.product_sales_id 
WHERE sales.sales_approved = '1' 
  AND sales.sales_approved_time > '$start_timestamp' 
  AND sales.sales_approved_time < '$end_timestamp'
GROUP BY product.product_id 
ORDER BY SUM(product_sold.product_quantity) DESC

但是LEFT OUTER JOIN的这个查询只给我一个销售产品的清单,我想要的还是显示尚未在列表中销售的产品。

这是使用sqlfiddle.com /#!2 / 967ee

的架构

1 个答案:

答案 0 :(得分:1)

此查询将有效,从SELECT产品表中的更多列添加到SELECTGROUP BY子句:

SELECT p.product_id
    ,SUM(IFNULL(ps.product_quantity,0)) AS product_quantity_sold
    ,SUM(IFNULL(ps.product_total_price,0)) AS total_price_sold 
FROM product p
LEFT JOIN product_sold ps ON p.product_id = ps.product_id
LEFT JOIN sales s ON ps.product_sales_id = s.sales_id
WHERE p.product_subcategory_id = $subcategory_id
  AND ( s.sales_id IS NULL
       OR ( s.sales_approved = '1' 
          AND s.sales_approved_time > '$start_timestamp'  
          AND s.sales_approved_time < '$end_timestamp'
          )
       )
GROUP BY p.product_id
ORDER BY SUM(IFNULL(ps.product_quantity,0)) DESC

<强>解释

如果您可以在product_sold_approved子句中使用product_sold_approved_timeWHERE而不是sales表中的值,则此查询会更简单。

LEFT JOIN product_soldLEFT JOIN表示您保留products表中的所有记录,而已售出的记录将加入每个product_sold条记录。然后对sales表执行相同的操作。

因此,在此阶段,您有很多行product + product_sold + sales,但您还拥有所有未售出的产品product + NULL + NULL。您需要过滤掉匹配的销售字段不符合条件的所有已加入记录,但您需要保留所有未能单独加入的记录。

要实现此目的,您需要一个WHERE子句,分别处理每组记录。 WHERE (condition A) OR (condition B)

条件A处理我们未售出的产品WHERE s.sales_id IS NULL - 所有无法加入促销的记录都包含在结果集中,并且不必与其他条件匹配。

s.sales_id不为NULL的

OR (sales_approved = 1 AND ... AND ...)记录必须通过where子句的这一半,因此我们会过滤掉不需要的销售。

最后,我们留下了一个结果集,其中包含所有没有任何销售额的记录+所有符合您条件的产品/ product_sales /销售记录。然后我们可以只使用GROUP BY product_id和SUM剩下的内容。

我的SQL中有IFNULL个,这是因为如果你总结了很多值,其中一些可能是NULL,如果单个值是NULL那么SUM的结果为NULLIFNULL(column,0)通过将任何NULL值转换为0来防止这种情况发生。 1 + NULL = NULL1 + 0 = 1 HOWEVER ,在反思中我可能不需要查询 - 删除它们,您应该注意到更改。