获得每个评分和平均值的投票总数。 Postgres

时间:2019-06-19 13:52:59

标签: postgresql

我有桌子:

| book_id | reader_id | rating
    1     |     2     |   1
    2     |     3     |   2
    2     |     2     |   5
    2     |     4     |   10

一个用户只能在1到10之间投票一次。

问题1:获得平均书评和每个评等票数的最佳方法是什么?喜欢:

 avr                     ratings
"3.6"   "2" "0" "0" "0" "0" "0" "0" "0" "1" "0"

现在我喜欢这样:

SELECT  
    AVG(rating),
    sum(case when rating  = 1 then 1  else 0 end) as r1,
    sum(case when rating  = 2 then 1  else 0 end) as r2,
    sum(case when rating  = 3 then 1  else 0 end) as r3,
    sum(case when rating  = 4 then 1  else 0 end) as r4,
    sum(case when rating  = 5 then 1  else 0 end) as r5,
    sum(case when rating  = 6 then 1  else 0 end) as r6,
    sum(case when rating  = 7 then 1  else 0 end) as r7,
    sum(case when rating  = 8 then 1  else 0 end) as r8,
    sum(case when rating  = 9 then 1  else 0 end) as r9,
    sum(case when rating  = 10 then 1  else 0 end) as r10
FROM books_rates
WHERE book_id=2;

问题2:为什么此查询的结果是对象?

{
       avg: '1.00000000000000000000',
       r1: '3',
       r2: '0',
       r3: '0',
       r4: '0',
       r5: '0',
       r6: '0',
       r7: '0',
       r8: '0',
       r9: '0',
       r10: '0'
     }

问题3:如果我在书本表中创建列,并将上面的查询结果存储在上面,这样一来会更好些,这样在每次加载书本时都不需要进行繁重的查询(是吗?)(当然这是如果有人给新的费率,结果列会更新)?

1 个答案:

答案 0 :(得分:1)

鉴于您的表中有干净的数据,这意味着您已经具有诸如书本和阅读器上的唯一键之类的约束,以禁止同一位用户为一本书投票两次,并且对等级字段进行约束,这将不允许您插入内容除[1..10]整数外,可能会使用以下窗口函数:

create table ratings (
  book_id int,
  reader_id int,
  rating int
);

insert into ratings (book_id, reader_id, rating) values 
(1,2,1),
(1,10,1),
(1,101,2),
(2,3,2),
(2,2,5),
(2,4,10);


select book_id, reader_id, rating, count(reader_id) over (partition by book_id, rating) as same_rating_votes, avg(rating) over(partition by book_id) as book_avg_rating from ratings;

select sq.book_id, sq.rating, max(sq.same_rating_votes) as     same_rating_votes, max(sq.book_avg_rating) as book_avg from (
    select book_id, reader_id, rating, count(reader_id) over (partition by book_id, rating) as same_rating_votes, avg(rating) over(partition by book_id) as book_avg_rating from ratings ) as sq
group by sq.book_id, sq.rating;

http://www.sqlfiddle.com/#!17/eb4ea/2

http://www.sqlfiddle.com/#!17/eb4ea/7

在每一行中,您都有对书的引用,读者,他的投票,该书的平均评分以及该书的相同票数。也许可以进一步将其与array_agg聚合在一起,或者如果您绝对需要将结果放在一行中,则可以使用这种方法。

谈到问题3,我相信如果您拥有数百万本书籍和票数,那么以物化视图计算所有内容并在晚上重新计算可能是一个合理的想法。