2014-04-03 107 views
1

在我目前的设置中,我有两个表:productrating执行“加权”SQL查询

产品表

  • PRODUCT_ID
  • 评级

product表包含了一大堆额外的信息,但对于这个问题,我专注于只有这两个领域。

评分表

  • PRODUCT_ID
  • 评级
  • USER_ID(谁评估)
  • is_admin - 对额定用户是否是管理员

原因布尔我们首先收集管理员评分,这是因为我们想要权衡管理员与普通用户(40%)相比,评分略高(60%)。 product表中的rating列等于所有管理员评分的AVG。在一般的评级是1和5

因此,对于每一个产品,我们必须考虑四个场景之间:

RATINGS BY  TOTAL 
USER ADMIN RATING 
---- ----- 
no no = 0 
yes no = AVG of user ratings (`ratings` table) 
yes yes = 0.6 AVG of admin ratings (`product_table`) + 0.4 AVG of user ratings (`ratings` table) 
no yes = AVG of admin ratings (`product_table`) 

目前检索数据集的SQL查询看起来是这样的:

$sql = "SELECT p.product_id, 
(COALESCE(p.rating,0)+COALESCE(j.sum,0))/(COALESCE(p.rating/p.rating,0) 
    + COALESCE(j.tot,0)) AS rating 
FROM product p 
LEFT JOIN 
    (SELECT SUM(rating) AS sum , 
     COUNT(rating) AS tot, 
     product_id FROM rating 
    WHERE is_admin_rating=FALSE GROUP BY product_id) j 
ON (p.product_id = j.product_id) LEFT JOIN product_description pd 
    ON (p.product_id = pd.product_id) LEFT JOIN product_to_store p2s 
    ON (p.product_id = p2s.product_id)"; 

然后,该查询会附加各种不同的排序选项(评级为默认值),此外,我们还使用LIMIT“分页”搜索结果。

有没有办法将加权评分纳入查询?或者我将不得不把它分解成几个查询?

+0

我重新编写了关于这四个场景的部分。我相信这更清楚。我无法理解您为所有场景获得“总评分”的方法,因此我没有对您的措辞做任何更改(但为了清楚起见,我建议您改进这些描述)。 – Smandoli

+0

谢谢!我将更新帖子以使其更加简洁 – AnuragBabaresco

+0

您是否拥有更多管理员,以便他们每个人可以对更多次产品评分?或者一个产品总是只有一个管理员评级? – shadyyx

回答

1

因为这显然看起来像一个基于Web的系统,我会强烈建议有轻微的非正规化和5列的产品表套结对

UserRatings, UserCount, AdminRatings, AdminCount, FinalRating 

当任何条目添加或更新评级表,你可以应用一个简单更新触发器,像

update Product p, 
     (select r.product_id, 
       sum(is_admin_rating=FALSE, 1, 0) as UserCount, 
       sum(is_admin_rating=FALSE, rating, 0) as UserRatings, 
       sum(is_admin_rating=TRUE, 1, 0) as AdminCount, 
       sum(is_admin_rating=TRUE, rating, 0) as AdminRatings 
      from Ratings r 
      where r.product_id = ProductIDThatCausedThisTrigger 
      group by r.product_id) as PreSum 
    set p.UserCount = PreSum.UserCount, 
     p.UserRatings = PreSum.UserRatings, 
     p.AdminrCount = PreSum.AdminCount, 
     p.AdminRatings = PreSum.AdminRatings, 
     p.FinalRating = case when PreSum.UserCount = 0 and PreSum.AdminCount = 0 
           then 0 
          when PreSum.UserCount = 0 
           then PreSum.AdminRatings/PreSum.AdminCount 
          when PreSum.AdminCount = 0 
           then PreSum.UserRatings/PreSum.UserCount 
          else 
           (PreSum.UserRatings/PreSum.UserCount * .4) 
          /(PreSum.AdminRatings/PreSum.AdminCount * .6) 
          end 
    where p.product_id = PreSum.product_id 

这样一来,你就永远没有做单独的连接,以收视率表,并做汇总,将只得到更多数据的积累速度较慢。然后你的查询可以使用表格,而不必担心结合,每个人的计数和他们的评级将在那里。

壳体/当针对FinalRatings基本上是做它都包起来作为用户计数和管理计数的组合可以是0/0,+/0,0/+或+/+

So, if no count for either, the case/when sets rating to 0 
if only the user count has a value, just get that average rating (userRatings/userCounts) 
if only the admin count has a value, get admin avg rating (adminRatings/adminCounts) 
if BOTH have counts, you are taking the respective averages * .4 and * .6 respectively. This would be the one factoring adjustment you might want to tweak. 

尽管查询本身看起来有些怪异和令人困惑,但如果您查看“PreSum”查询,则仅针对刚刚进行评分的1种产品以及触发基础进行查询。然后,根据单个产品ID加入的结果进行简单更新。

使用此功能可能会为您提供更好的长期解决方案。

+0

谢谢!我会测试一下这个建议...... – AnuragBabaresco

+0

这很有效,但是以一种“呃”的方式 - 我意识到我现有的'product_table'中的'rating'字段可以保持您建议添加的最终评分。所以我一直在我面前回答问题,而你的明智回应恰恰说明了这一点。非常感谢! – AnuragBabaresco

+0

@AuuragBabaresco,有时我们看不到眼前的事情,直到我们让别人戴眼镜来帮助重新焕然一新。当长期被埋没在项目中时,我们可以忘记或忽略我们认为我们所知道的与实际情况。 – DRapp