2015-11-16 7 views
0

У меня есть таблица project_product и таблица project_consummation. Люди потребляют продукт, и может дать продукту оценку от 1 до 10.Подведение итогов оценки для многих продуктов

Позвольте мне ASCII искусство для осветления:

+--------------------------+  +-------------------------+ 
| project_product   |  | project_consummation | 
|--------------------------|  |-------------------------| 
| id integer primary key |-\ | id integer primary key | 
| name varchar    | \->| product_id integer  | 
| ...      |  | rating  integer  | 
| various other fields... |  | user_id integer  | 
+--------------------------+  | ...      | 
           | various other fields... | 
           +-------------------------+ 

Теперь я хочу обзор голосов для продукта. Конечно, может быть consummation s без значения rating (например, NULL), поэтому их необходимо игнорировать.

Результат должен выглядеть следующим образом (каждый рейтинг от 1 до 10 должен иметь свой столбец, указывающий количество людей, которые дали продукт этот рейтинг, а также общее количество рейтингов num_ratings и, возможно, позже некоторые медианные, стандартные отклонение и т.д.):

product_id | rating1 | rating2 | ... |rating10 | num_ratings 
------------+---------+---------+-----+---------+------------- 
     1002 |   |   | ... |  1 |   1 
     1014 |  4 |   | ... |  2 |   6 
     1015 |  2 |  1 | ... |  1 |   4 

Я создал «решение», которое является довольно неуклюжим, потому что я делаю LEFT OUTER JOIN для каждого рейтинга колонки, как это (я только показать первые 3 колонки, но я уверен, вы увидите, какой беспорядок это станет):

SELECT p.id AS product_id, 
     rating1, rating2, rating3, 
     COALESCE(rating1, 0) + COALESCE(rating2, 0) + COALESCE(rating3, 0) AS num_ratings 
    FROM project_product p 
    LEFT OUTER JOIN 
     (SELECT product_id, 
       count(*) AS rating1 
      FROM project_consummation c 
      WHERE rating = 1 
      GROUP BY product_id 
     ) c1 ON p.id = c1.product_id 
    LEFT OUTER JOIN 
     (SELECT product_id, 
       count(*) AS rating2 
      FROM project_consummation c 
      WHERE rating = 2 
      GROUP BY product_id 
     ) c2 ON p.id = c2.product_id 
    LEFT OUTER JOIN 
     (SELECT product_id, 
       count(*) AS rating3 
      FROM project_consummation c 
      WHERE rating = 3 
      GROUP BY product_id 
     ) c3 ON p.id = c3.product_id 

Что было бы лучшим решением в отношении лучшего кода и особенно лучшей производительности?

+0

Есть еще 2 способа сделать это, Используя перекрестную функцию, которая будет величина быстрее, чем ваш «неуклюжий» ПОДХОД и другое мое предложение приемлемо, используя операторы случае как «сумма (случай, когда рейтинг = 1, то 1 else 0 end) как рейтинг1, сумма (случай, когда рейтинг = 2, а затем еще 1 конец 0) как рейтинг2 .... " –

+0

Это выглядит как интересный ответ. Не могли бы вы создать реальный ответ из своего комментария? – mawimawi

+1

Я могу, через полчаса .... бит занят –

ответ

2

Делают это так:

select 
     p.id product_id, 
     count(case when c.rating = 1 then 1 else null end) rating1, 
     count(case when c.rating = 2 then 1 else null end) rating2, 
     count(case when c.rating = 3 then 1 else null end) rating3, 
     count(case when c.rating = 4 then 1 else null end) rating4, 
     count(case when c.rating = 5 then 1 else null end) rating5, 
     count(case when c.rating = 6 then 1 else null end) rating6, 
     count(case when c.rating = 7 then 1 else null end) rating7, 
     count(case when c.rating = 8 then 1 else null end) rating8, 
     count(case when c.rating = 9 then 1 else null end) rating9, 
     count(case when c.rating = 10 then 1 else null end) rating10, 
     count(c.rating) num_ratings 
    from project_product p 
    left join project_consummation c on c.product_id = p.id 
     group by p.id 
     order by p.id; 

или немного короче форма для оценки:

select 
      p.id product_id, 
      count(nullif(c.rating = 1, false)) rating1, 
      count(nullif(c.rating = 2, false)) rating2, 
      count(nullif(c.rating = 3, false)) rating3, 
      count(nullif(c.rating = 4, false)) rating4, 
      count(nullif(c.rating = 5, false)) rating5, 
      count(nullif(c.rating = 6, false)) rating6, 
      count(nullif(c.rating = 7, false)) rating7, 
      count(nullif(c.rating = 8, false)) rating8, 
      count(nullif(c.rating = 9, false)) rating9, 
      count(nullif(c.rating = 10, false)) rating10, 
      count(c.rating) num_ratings 
     from project_product p 
     left join project_consummation c on c.product_id = p.id 
      group by p.id 
      order by p.id; 
1

не совершенен ... но надеюсь, что вы получите идею

используя случай

SELECT project_product.id,project_product.name 
    , sum(case when rating = 1 then 1 else 0 end) as rating1 
    , sum(case when rating = 2 then 1 else 0 end) as rating2 
    , sum(case when rating = 3 then 1 else 0 end) as rating3 
    , sum(case when rating = 4 then 1 else 0 end) as rating4 
    , sum(case when rating = 5 then 1 else 0 end) as rating5 
    , sum(case when rating = 6 then 1 else 0 end) as rating6 
    , sum(case when rating = 7 then 1 else 0 end) as rating7 
    , sum(case when rating = 8 then 1 else 0 end) as rating8 
    , sum(case when rating = 9 then 1 else 0 end) as rating9 
    , sum(case when rating = 10 then 1 else 0 end) as rating10 
    FROM project_product 
    LEFT JOIN project_consummation ON (project_product.id = project_consummation.product_id) 
    GROUP BY project_product.id, project_product.name 

и с использованием cr osstab:

-- if necessary: 
-- CREATE EXTENSION tablefunc; 

SELECT project_product.id, 
     rating1, rating2, rating3, rating4, rating5, 
     rating6, rating7, rating8, rating9, rating10, 
     rating1+rating2+rating3+rating4+rating5+ 
     rating6+rating7+rating8+rating9+rating10 as num_ratings 
    FROM project_product 
    LEFT JOIN crosstab(
     'select product_id, rating, count(*) 
      from project_consummation 
     group by product_id, rating 
     order by product_id, rating ', 
     'select generate_series(1, 10)') 
     AS main (
     id integer, rating1 integer, rating2 integer, rating3 integer, 
     rating4 integer, rating5 integer, rating6 integer, 
     rating7 integer, rating8 integer, rating9 integer, rating10 integer 
     ) ON (project_product.id = main.id) 
Смежные вопросы