这是我的疑问:
SELECT `products`.*, SUM(orders.total_count) AS revenue,
SUM(orders.quantity) AS qty, ROUND(AVG(product_reviews.stars)) as avg_stars
FROM `products`
LEFT JOIN `orders`
ON (`products`.`id` = `orders`.`product_id`) AND
(`orders`.`status` = 'delivered' OR `orders`.`status` = 'new')
LEFT JOIN product_reviews
ON (products.id = product_reviews.product_id)
GROUP BY `products`.`ID`
ORDER BY products.ID DESC
LIMIT 10
OFFSET 0
当我有第二个左连接时,我的第一个左连接数据,来自订单表的收入和数量给了我根本不正确的值(太高,很多双打?)
我得到的方向是我得到半笛卡尔产品,所以对产品的两次评论是数量加倍,我相信这是我的问题。
如何解决这个问题?
答案 0 :(得分:3)
问题是product_reviews
和orders表每个产品ID可以有多一行。解决此问题的一种方法是使用子查询:
SELECT `products`.*,
o.revenue,
o.qty,
ROUND(avg_stars) as avg_stars
FROM `products`
LEFT JOIN
(
select `product_id`,
sum(total_count) revenue,
sum(quantity) qty
from `orders`
where `status` in ('delivered', 'new')
group by `product_id`
) o
ON `products`.`id` = o.`product_id`
LEFT JOIN
(
select product_id, avg(stars) avg_stars
from product_reviews
group by product_id
) pr
ON (products.id = pr.product_id)
ORDER BY products.ID DESC
LIMIT 10
OFFSET 0
答案 1 :(得分:1)
避免该问题的一种方法是在SELECT列表中使用相关子查询,而不是左连接。
SELECT p.*
, SUM(o.total_count) AS revenue
, SUM(o.quantity) AS qty
, ( SELECT ROUND(AVG(r.stars))
FROM `product_reviews` r
WHERE r.product_id = p.id
) AS avg_stars
FROM `products` p
LEFT
JOIN `orders` o
ON o.product_id = p.id
AND o.status IN ('delivered','new')
GROUP BY p.id
ORDER BY p.id DESC
LIMIT 10
OFFSET 0
这不是唯一的方法,并不一定是最好的方法,特别是对于大型集合但是鉴于子查询最多运行10次(给定LIMIT子句),性能应该合理(给定一个合适的方法) product_reviews(product_id,stars)
上的索引。
如果要返回所有产品ID或其中很大一部分,那么使用内联视图可能会提供更好的性能(避免在选择列表中执行相关子查询的嵌套循环)
SELECT p.*
, SUM(o.total_count) AS revenue
, SUM(o.quantity) AS qty
, s.avg_stars
FROM `products` p
LEFT
JOIN `orders` o
ON o.product_id = p.id
AND o.status IN ('delivered','new')
LEFT
JOIN ( SELECT ROUND(AVG(r.stars)) AS avg_stars
, r.product_id
FROM `product_reviews` r
GROUP BY r.product_id
) s
ON s.product_id = p.id
GROUP BY p.id
ORDER BY p.id DESC
LIMIT 10
OFFSET 0
请注意:原始查询的问题在于产品的每个订单都与产品的每次审核相匹配。
如果我对“半笛卡尔”一词的使用产生误导或混淆,我道歉。
我想要表达的想法是,您有两个不同的集合(产品的订单集和产品的评论集),并且您的查询生成了“交叉产品”这两个不同的集合,基本上“匹配”每个订单到每个评论(对于特定产品)。
例如,给定product_id 101的reviews
中的三行,以及product_id 101的orders
中的两行,例如:
REVIEWS
pid stars text
--- ----- --------------
101 4.5 woo hoo perfect
101 3 ehh
101 1 totally sucked
ORDERS
pid date qty
--- ----- ---
101 1/13 100
101 1/22 7
您的原始查询实际上是在形成一个结果集,其中包含六行,每行从订单匹配到评论中的所有三行:
id date qty stars text
--- ---- ---- ---- ------------
101 1/13 100 4.5 woo hoo perfect
101 1/13 100 3 ehh
101 1/13 100 1 totally sucked
101 1/22 7 4.5 woo hoo perfect
101 1/22 7 3 ehh
101 1/22 7 1 totally sucked
然后,当应用了qty上的SUM聚合时,返回的值比你预期的要大。
答案 2 :(得分:1)
如果没有看到你的表架构,就很难解决这个问题, 我建议你首先查看你的Aggregations和Group By语句,然后查看你的列默认值,你如何处理空值,还要看聚合函数中的DISTINCT。
如果所有其他方法都失败并且“优化”解决方案并不重要且您的数据量很低,那么仅在您需要值的表上进行“子选择”,在“1选择”表中的“选择”行中,您的行数要窄一些范围,它将产生正确的结果。
我建议您在这里提供表格模式。