SQL查询LEFT OUTER JOIN广告与AVG(评级)

时间:2017-09-27 23:11:47

标签: mysql join

我有一张包含以下表格的数据库:

ads
ads_rating
ads_province
ads_promo
etc...

我生成了一个复杂的查询,因为我需要某些广告,每个广告的平均评分为。

在ads_rating表中我有和id,rating,user_id,date_rated

如何加入广告。*表并添加一个名为" rating_average"的新字段。或类似的东西。

我想我必须在JOIN中创建一个SELECT,但我是MySQL的新手。

这是我的实际功能查询:

SELECT
category.id AS category_id,
category.subcat AS category_name,
category.`desc` AS category_desc,
category.`name` AS category_pretty_name,
ads.id,
ads.header,
ads.price,
ads.oldprice,
ads.sellfast,
ads.`hash`,
ads.foto1,
ads.foto2,
ads.foto3,
ads.foto4,
ads.foto5,
ads.user_id,
SUBSTR(ads.body, 1, 160) AS body,
ads.subcat_id,
ads.updated,
ads.created,
ads.email,
ads.`name`,
ads.phone,
ads.hits,
ads.hidden,
promo.promotype AS promo_type,
supercategory.`name` AS supercategory_name,
supercategory.id AS supercategory_id,
ads_rating.rating,
promo.ads_id
FROM `ads` 
JOIN `category` ON `category`.`id` = `ads`.`subcat_id` 
JOIN `supercategory` ON `supercategory`.`id` = `category`.`cat`  
LEFT OUTER JOIN `promo` ON `promo`.`ads_id` = `ads`.`id` 
LEFT OUTER JOIN ads_rating ON `ads_rating`.`ad_id` = `ads`.`id`
WHERE `recycle_bin` != 1 AND `hidden` =0 AND ( `promo`.`promotype` >0 OR `ads`.`user_id` = 20 OR `ads_rating`.`rating` >= 4 )
ORDER BY `promo_type` DESC, `updated` DESC
LIMIT 5000

不知道如何管理这条线:

LEFT OUTER JOIN ads_rating ON `ads_rating`.`ad_id` = `ads`.`id`

示例数据:

广告
ID |标题|身体|类别|等等
2 |漂亮的瞳孔|它的新| puppys |等
3 |丑陋的傀儡|它的老| puppys | etc

评级
ID | ad_id | USER_ID |评级| rated_date
1 | 2 | 568 | 5 | 2017年10月2日
1 | 2 | 570 | 4 | 2017年10月3日
1 | 2 | 594 | 5 | 2017-10-1

因此,所需的结果集必须是

ID |头|体|类别| AVG_RATING
2 |漂亮的瞳孔|它是新的| puppys | 4.6
3 |丑陋的傀儡|它的老| puppys | null

谢谢!

3 个答案:

答案 0 :(得分:1)

您使用的LEFT [OUTER] JOIN语法似乎没问题,但我们无权访问任何样本数据来验证。但是,您的查询有一个方面可能会令人困惑,这是您在where子句AND ads_rating.rating >= 4中引入的额外条件。

我认为您可能会发现在连接中包含额外条件而不是在where子句中更容易,例如:

select ...

FROM `ads` 
JOIN `category` ON `category`.`id` = `ads`.`subcat_id` 
JOIN `supercategory` ON `supercategory`.`id` = `category`.`cat`  
LEFT OUTER JOIN `promo` ON `promo`.`ads_id` = `ads`.`id` 
LEFT OUTER JOIN ads_rating ON `ads_rating`.`ad_id` = `ads`.`id`
                          AND `ads_rating`.`rating` >= 4
WHERE `recycle_bin` != 1 
AND `hidden` =0 
AND ( `promo`.`promotype` >0 
   OR `ads`.`user_id` = 20
    )
ORDER BY `promo_type` DESC, `updated` DESC
LIMIT 5000

这样做的原因是LEFT JOIN将允许返回ads表中的一行,即使没有相应的ads_rating信息,因此来自ads_rating的任何列都将发生这种情况时为NULL。 e.g。

 ads.id ads_rating.rating
 1      4
 2      NULL

如果你的where子句包含AND ads_rating.rating >= 4,则id 2将被排除在最终结果之外,因此该谓词有效地使LEFT JOIN成为INNER JOIN的等价物。

因此。当使用任何OUTER连接(例如LEFT OUTER JOIN)时,要非常谨慎地引用where子句中的那些表。通常,将这些额外条件放入连接中会更简单。

答案 1 :(得分:1)

因此,如果您直接将广告加入此表格,您将获得针对特定广告的每个评分的行。因此,如果您只想获得平均评分而不是每个评分,那么您需要将ads_rating.rating更改为AVG(ads_rating.rating)并将其他所有内容分组。这会为您提供每个广告的平均评分。

SELECT
category.id AS category_id,
category.subcat AS category_name,
category.desc AS category_desc,
category.name AS category_pretty_name,
ads.id,
ads.header,
ads.price,
ads.oldprice,
ads.sellfast,
ads.hash,
ads.foto1,
ads.foto2,
ads.foto3,
ads.foto4,
ads.foto5,
ads.user_id,
SUBSTR(ads.body, 1, 160) AS body,
ads.subcat_id,
ads.updated,
ads.created,
ads.email,
ads.name,
ads.phone,
ads.hits,
ads.hidden,
promo.promotype AS promo_type,
supercategory.name AS supercategory_name,
supercategory.id AS supercategory_id,
**AVG(ads_rating.rating) as rating_average,**
promo.ads_id
FROM ads 
inner join category ON category.id = ads.subcat_id 
inner join supercategory ON supercategory.id = category.cat  
LEFT OUTER JOIN promo ON promo.ads_id = ads.id 
LEFT OUTER JOIN ads_rating ON ads_rating.ad_id = ads.id
WHERE recycle_bin != 1 AND hidden = 0 AND ( promo.promotype > 0 OR ads.user_id = 20 OR ads_rating.rating >= 4 )
GROUP BY
category.id AS category_id,
category.subcat AS category_name,
category.desc AS category_desc,
category.name AS category_pretty_name,
ads.id,
ads.header,
ads.price,
ads.oldprice,
ads.sellfast,
ads.hash,
ads.foto1,
ads.foto2,
ads.foto3,
ads.foto4,
ads.foto5,
ads.user_id,
SUBSTR(ads.body, 1, 160) AS body,
ads.subcat_id,
ads.updated,
ads.created,
ads.email,
ads.name,
ads.phone,
ads.hits,
ads.hidden,
promo.promotype AS promo_type,
supercategory.name AS supercategory_name,
supercategory.id AS supercategory_id
ORDER BY promo_type DESC, updated DESC
LIMIT 5000

另一种选择是实际加入两个单独的查询...见下文。实际上你正在做的是接受2个查询并加入它们就好像它们是表格一样。第二个不太理想,但如果您要汇总来自不同来源的不同数据,则可能非常有用,例如,如果您从促销和评级中提取平均值,并且需要在1个查询的结果中显示它们。

select q1.*, q2.average_rating 
from
(
SELECT
category.id AS category_id,
category.subcat AS category_name,
category.desc AS category_desc,
category.name AS category_pretty_name,
ads.id as ads_id,
ads.header,
ads.price,
ads.oldprice,
ads.sellfast,
ads.hash,
ads.foto1,
ads.foto2,
ads.foto3,
ads.foto4,
ads.foto5,
ads.user_id,
SUBSTR(ads.body, 1, 160) AS body,
ads.subcat_id,
ads.updated,
ads.created,
ads.email,
ads.name,
ads.phone,
ads.hits,
ads.hidden,
promo.promotype AS promo_type,
supercategory.name AS supercategory_name,
supercategory.id AS supercategory_id
FROM ads 
inner join category ON category.id = ads.subcat_id 
inner join supercategory ON supercategory.id = category.cat  
LEFT OUTER JOIN promo ON promo.ads_id = ads.id 
LEFT OUTER JOIN ads_rating ON ads_rating.ad_id = ads.id
WHERE recycle_bin != 1 AND hidden = 0 AND ( promo.promotype > 0 OR ads.user_id = 20 OR ads_rating.rating >= 4 )
) q1
LEFT OUTER JOIN 
(
select ads_id, avg(rating) as average_rating  from ads_rating 
group by ads_id
) q2
on q1.ads_id = q2.ads_id
ORDER BY promo_type DESC, updated DESC
LIMIT 5000

希望这会有所帮助。如果有任何错别字,我道歉。我在记事本中这样做了。解决任何错误,我会向您发送修复

答案 2 :(得分:0)

到目前为止,这是我能找到的最佳解决方案,感谢@ beautiful.drifter

SELECT q1.*, q2.average_rating FROM (
                    SELECT category.id AS category_id,
                    category.subcat AS category_name,
                    category.desc AS category_desc,
                    category.name AS category_pretty_name,
                    ads.id as ads_id,
                    ads.header,
                    ads.price,
                    ads.oldprice,
                    ads.sellfast,
                    ads.hash,
                    ads.foto1,
                    ads.foto2,
                    ads.foto3,
                    ads.foto4,
                    ads.foto5,
                    ads.user_id,
                    SUBSTR(ads.body, 1, 160) AS body,
                    ads.subcat_id,
                    ads.updated,
                    ads.created,
                    ads.email,
                    ads.name,
                    ads.phone,
                    ads.hits,
                    ads.hidden,
                    ads.recycle_bin,
                    promo.promotype AS promo_type,
                    supercategory.name AS supercategory_name,
                    supercategory.id AS supercategory_id
                    FROM ads 
                    INNER JOIN category ON category.id = ads.subcat_id 
                    INNER JOIN supercategory ON supercategory.id = category.cat  
                    LEFT OUTER JOIN promo ON promo.ads_id = ads.id 
                    ) q1
                    LEFT OUTER JOIN (
                    SELECT ad_id, avg(rating) as average_rating from ads_rating 
                    group by ad_id
                    ) q2
                    ON q1.ads_id = q2.ad_id
                    WHERE q1.recycle_bin != 1 AND q1.hidden = 0 AND ( q1.promo_type > 0 OR q2.average_rating >= 4 )
                    ORDER BY promo_type DESC, updated DESC