GROUP BY и 2 ПРЕДЕЛЫ - PullRequest
       16

GROUP BY и 2 ПРЕДЕЛЫ

1 голос
/ 21 октября 2019

Представьте себе эту таблицу

Name | Date | Value
--------------------
Olli | 2019 | 2
Olli | 2018 | 2
Olli | 2017 | 2
Olli | 2016 | 1
Olli | 2015 | 1
Olli | 2014 | 1
Pete | 2019 | 3
Pete | 2018 | 3
Pete | 2017 | 3
Pete | 2016 | 2
Pete | 2015 | 9

Я хочу выбрать частное от кратковременного среднего (последние 3 строки) и среднего значения за каждое имя:

Olli: 2 / 1.5 = 1.3333
Pete: 3 / 4 = 0.75

Без группировки по имени я могу легко выбрать все компоненты:

SELECT MEAN(value) FROM tbl WHERE name = 'Olli' -- all time mean, used directly in final query 

-- for the short term mean I use a CTE:
WITH short_term_tbl AS (SELECT * FROM tbl WHERE name = 'Olli' ORDER BY Date DESC LIMIT 3)
    SELECT MEAN(short_term_tbl.value) / MEAN(table.value)
    FROM short_term_tbl, tbl

Но как я могу обобщить это для всех имен?

Я был бы очень рад найти решение, котороеработает как на mysql, так и на postgresql.

Ответы [ 2 ]

3 голосов
/ 21 октября 2019

В MySQL 8.0 (который вы, похоже, используете, поскольку вы используете CTE, который доступен только начиная с этой версии MySQL), это можно сделать следующим образом, используя row_number():

select name, avg(case when rn <= 3 then value end) / avg(value)
from (
    select t.*, row_number() over(partition by name order by date desc) rn from mytable t
) t
group by name

Подзапросы присваивают ранг каждой записи в группах, совместно использующих один и тот же name, или упорядочивают по убыванию date. Тогда внешний запрос выполняет условную агрегацию.

1 голос
/ 21 октября 2019

Вот один из способов получить пользовательское среднее:

SELECT Name, 
  AVG(CASE WHEN RowNum <=3 THEN Value END) / AVG(Value) AS avg_custom
FROM (
  SELECT Name, Date, Value,
    ROW_NUMBER() OVER(
      PARTITION BY Name ORDER BY Date DESC -- Rank rows by date, within "name" groups
    ) AS RowNum
  FROM tbl
) src
GROUP BY Name
;

Это должно работать и в Postgres.

DB Fiddle

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...