2

データベースに次のテーブルがあります

  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

私はこの記事を見ていて、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

4

2 に答える 2

2

Postgres のOperatorWITHは、メイン クエリで使用される追加の作業クエリを作成するためにのみ使用されます。

このクエリは、代わりに 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)
于 2012-12-20T06:17:15.590 に答える
1

SQL フィドル

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 |                                   
于 2012-12-20T10:55:15.030 に答える