6 лучших мин средних элементов postgresql - PullRequest
0 голосов
/ 18 января 2019

Мне нужно посчитать среднюю цену и сгруппировать их по 2 колонкам.Затем выберите 2 верхних значения (PostgreSQL 10.1).Например, у меня есть следующие структуры:

------------------------------------------------------------------------------------------
        category        | shop_name |     price |      date     |
MSI GeForce RTX 2080    |amazon     |   62649   |   1/6/2019    |   
MSI GeForce RTX 2080    |amazon     |   58668   |   1/17/2019   |   
MSI GeForce RTX 2080    |amazon     |   62649   |   1/7/2019    |   
MSI GeForce RTX 2080    |amazon     |   60542   |   1/16/2019   |   
MSI GeForce RTX 2080    |amazon     |   62649   |   1/5/2019    |   
MSI GeForce RTX 2080    |brandstar  |   66456   |   1/16/2019   |   
MSI GeForce RTX 2080    |brandstar  |   66347   |   1/17/2019   |   
MSI GeForce RTX 2080    |brandstar  |   66456   |   1/16/2019   |   
MSI GeForce RTX 2080    |brigo      |   63300   |   1/17/2019   |   
MSI GeForce RTX 2080    |brigo      |   65330   |   1/16/2019   |   
MSI GeForce RTX 2080    |brigo      |   65330   |   1/16/2019   |
MSI GeForce RTX 2070    | fake_shop |   65330   |   1/16/2019   |
MSI GeForce RTX 2070    | fake_shop |   65330   |   1/17/2019   |
MSI GeForce RTX 2070    | fake_shop |   65330   |   1/18/2019   |

Предположим, я хочу выбрать 2 лучших средних результата для категории и shop_name.Поэтому я ожидаю следующий результат:


        category        | shop_name |     price |      date     |     avg   |
MSI GeForce RTX 2080    |amazon     |   62649   |   1/6/2019    |   61431.4 |1
MSI GeForce RTX 2080    |amazon     |   58668   |   1/17/2019   |   61431.4 |1  
MSI GeForce RTX 2080    |amazon     |   62649   |   1/7/2019    |   61431.4 |1  
MSI GeForce RTX 2080    |amazon     |   60542   |   1/16/2019   |   61431.4 |1  
MSI GeForce RTX 2080    |amazon     |   62649   |   1/5/2019    |   61431.4 |1  
MSI GeForce RTX 2080    |brandstar  |   66456   |   1/16/2019   |   66419.66667 |  3
MSI GeForce RTX 2080    |brandstar  |   66347   |   1/17/2019   |   66419.66667 |  3
MSI GeForce RTX 2080    |brandstar  |   66456   |   1/16/2019   |   66419.66667 |  3
MSI GeForce RTX 2080    |brigo      |   63300   |   1/17/2019   |   64653.33333 |  2
MSI GeForce RTX 2080    |brigo      |   65330   |   1/16/2019   |   64653.33333 |  2
MSI GeForce RTX 2080    |brigo      |   65330   |   1/16/2019   |   64653.33333 |  2
MSI GeForce RTX 2070    | fake_shop |   65330   |   1/16/2019   |   65330   | 1
MSI GeForce RTX 2070    | fake_shop |   65330   |   1/17/2019   |   65330   | 1
MSI GeForce RTX 2070    | fake_shop |   65330   |   1/18/2019   |   65330   | 1

Тогда я бы хотел выбрать строки, где ранг меньше 3.

Но я получаю следующий результат:

    ---------------------------------------------------------------------------------------------
    MSI GeForce RTX 2080    |amazon     |   62649   |   1/6/2019    |   61431.4 |   1   |
    MSI GeForce RTX 2080    |amazon     |   58668   |   1/17/2019   |   61431.4 |   1   |
    MSI GeForce RTX 2080    |amazon     |   62649   |   1/7/2019    |   61431.4 |   1   |
    MSI GeForce RTX 2080    |amazon     |   60542   |   1/16/2019   |   61431.4 |   1   |
    MSI GeForce RTX 2080    |amazon     |   62649   |   1/5/2019    |   61431.4 |   1   |
    MSI GeForce RTX 2080    |brandstar  |   66456   |   1/16/2019   |   66419.66667 |   1   |
    MSI GeForce RTX 2080    |brandstar  |   66347   |   1/17/2019   |   66419.66667 |   1   |
    MSI GeForce RTX 2080    |brandstar  |   66456   |   1/16/2019   |   66419.66667 |   1   |
    MSI GeForce RTX 2080    |brigo      |   63300   |   1/17/2019   |   64653.33333 |   1   |
    MSI GeForce RTX 2080    |brigo      |   65330   |   1/16/2019   |   64653.33333 |   1   |
    MSI GeForce RTX 2080    |brigo      |   65330   |   1/16/2019   |   64653.33333 |   1   |
    MSI GeForce RTX 2070    | fake_shop |   65330   |   1/16/2019   |   65330   | 1
    MSI GeForce RTX 2070    | fake_shop |   65330   |   1/17/2019   |   65330   | 1
    MSI GeForce RTX 2070    | fake_shop |   65330   |   1/18/2019   |   65330   | 1

Вот мой SQL-запрос:

SELECT tt.category,
       tt.shop_name,
       tt.price,
       tt.updated,
       tt.avg_price,
       rank() OVER (PARTITION BY tt.category,
                                 tt.shop_name,
                                 tt.avg_price
                    ORDER BY tt.avg_price DESC)
FROM
  ( SELECT category,
           LOWER(shop_name) AS shop_name,
           CAST (price AS INTEGER) AS price,
                DATE(updated) AS updated,
                avg(price) OVER (PARTITION BY category,
                                              LOWER(shop_name)) AS avg_price
   FROM prices ) AS tt

Ответы [ 2 ]

0 голосов
/ 18 января 2019

Я думаю, что вы хотите:

select tt.category,  tt.shop_name, tt.price,  tt.updated, tt.avg_price,
       dense_rank() over (partition by tt.category order by tt.avg_price desc)
from (select category, lower(shop_name) as shop_name,
             (price::int) as price, updated::date as updated,
             avg(price) over (partition by category,  lower(shop_name)) as avg_price 
      from prices
     ) tt

Я упростил некоторую логику, но главное изменение - partition by для rank(). Вы, кажется, хотите рейтинг для каждого магазина. dense_rank() также более уместно.

Если вы хотите дифференцировать категории с одинаковой перерасходом:

       dense_rank() over (partition by tt.shop_name order by tt.avg_price desc, category)
0 голосов
/ 18 января 2019

Просто используйте AVG() OVER (), а затем DENSE_RANK():

WITH cte1 AS (
    SELECT *, AVG(price) OVER (PARTITION BY category, shop_name) AS avg_price
    FROM prices
), cte2 AS (
    SELECT *, DENSE_RANK() OVER (PARTITION BY category ORDER BY avg_price) AS rnk
    FROM cte1
)
SELECT *
FROM cte2
WHERE rnk <= 2
ORDER BY category, shop_name
...