postgresql中的贝叶斯评级

时间:2012-12-20 01:31:33

标签: database postgresql

我的db

中有以下表格
  Name     |    total_stars   |      total_reviews
 Item A             27                       7
 Item B             36                       9
 Item C             27                       7
 Item D             30                       6
 Item E             0                        0
 Item F             0                        0
 Item F             15                       3

我正在查看this article,并试图在postgresql数据库中实现贝叶斯排名。

为等级给出的公式是

br = ( (avg_num_votes * avg_rating) + (this_num_votes * this_rating) ) / 
(avg_num_votes + this_num_votes)

其中:

  • avg_num_votes:所有具有num_votes> 0的项目的平均投票数
  • avg_rating:每件商品的平均评分(同样,那些有num_votes> 0的商品)
  • this_num_votes:此项目的投票数
  • this_rating:此商品的评级

这是我提出的查询,但它不起作用:

with avg_num_votes as (
      select AVG(total_reviews) 
           from business 
           where total_reviews != 0), 
       avg_rating as (
          select AVG(total_stars/total_reviews) 
          from business 
          where total_reviews != 0)
select * from business 
  order by ((avg_num_votes * avg_rating) + (total_stars)) / (avg_num_votes + total_reviews);

我得到:ERROR: column "avg_num_votes" does not exist

2 个答案:

答案 0 :(得分:2)

Postgres中的运算符WITH仅用于创建要在主查询中使用的其他工作查询。

此查询正在使用FROM子句中的子选择,并按预期工作:

SELECT business.* FROM business,
     (SELECT avg(total_reviews) AS v
      FROM business 
      WHERE total_reviews != 0
     ) AS avg_num_votes,
     (SELECT avg(total_stars/total_reviews) AS v 
      FROM business 
      WHERE total_reviews != 0
     ) AS avg_rating
ORDER BY ((avg_num_votes.v * avg_rating.v) + (total_stars)) / (avg_num_votes.v + total_reviews)

编辑:实际上,使用WITH也是可能的,但与第一种形式相比似乎没有更短。此外,它不太便携 - 第一个解决方案将适用于MySQL,但这不会:

WITH
    avg_num_votes AS (
        SELECT avg(total_reviews) AS v
        FROM business 
        WHERE total_reviews != 0
    ),
    avg_rating AS (
        SELECT avg(total_stars/total_reviews) AS v
        FROM business
        WHERE total_reviews != 0
    )
SELECT business.*
FROM business, avg_num_votes, avg_rating
ORDER BY ((avg_num_votes.v * avg_rating.v) + (total_stars)) / (avg_num_votes.v + total_reviews)

答案 1 :(得分:1)

SQL Fiddle

with av as (
    select avg(total_reviews) avg_num_votes
    from business
    where total_reviews > 0
), ar as (
    select name, avg(total_stars * 1.0 / total_reviews) avg_rating
    from business
    where total_reviews > 0
    group by name
)
select b.*, avg_rating, avg_num_votes,
    (avg_num_votes * avg_rating + total_stars)
    /
    (avg_num_votes + total_reviews) br
from
    business b
    left join
    ar on ar.name = b.name
    inner join
    av on true
order by br, b.name
    ;
  name  | total_stars | total_reviews |     avg_rating     |   avg_num_votes    |                 br                 
--------+-------------+---------------+--------------------+--------------------+------------------------------------
 Item A |          27 |             7 | 3.8571428571428571 | 6.4000000000000000 | 3.85714285714285712238805970149254
 Item C |          27 |             7 | 3.8571428571428571 | 6.4000000000000000 | 3.85714285714285712238805970149254
 Item B |          36 |             9 | 4.0000000000000000 | 6.4000000000000000 | 4.00000000000000000000000000000000
 Item D |          30 |             6 | 5.0000000000000000 | 6.4000000000000000 | 5.00000000000000000000000000000000
 Item F |           0 |             0 | 5.0000000000000000 | 6.4000000000000000 | 5.00000000000000000000000000000000
 Item F |          15 |             3 | 5.0000000000000000 | 6.4000000000000000 | 5.00000000000000000000000000000000
 Item E |           0 |             0 |                    | 6.4000000000000000 |