Скользящее среднее SQL / BIGQUERY с GAP в датах - PullRequest
0 голосов
/ 22 сентября 2018

У меня проблемы со скользящей средней в BigQuery / SQL, у меня есть таблица «SCORES», и мне нужно сделать 30-дневную скользящую среднюю при группировке данных с использованием пользователей, проблема в том, что мои даты не последовательные, напримерв ней есть пробелы.

Ниже мой текущий код:

SELECT user, date,
      AVG(score) OVER (PARTITION BY user ORDER BY date)
FROM SCORES;

Я не знаю, как добавить ограничения даты в эту строку или, если это вообще возможно.

Моя текущая таблица выглядит так, но, конечно, с гораздо большим количеством пользователей:

user    date    score
AA  13/02/2018  2.00
AA  15/02/2018  3.00
AA  17/02/2018  4.00
AA  01/03/2018  5.00
AA  28/03/2018  6.00

Тогда мне нужно, чтобы она стала такой:

user    date    score   30D Avg
AA  13/02/2018  2.00    2.00
AA  15/02/2018  3.00    2.50
AA  17/02/2018  4.00    3.00
AA  01/03/2018  5.00    3.50
AA  28/03/2018  6.00    5.50

Где вВ последней строке измеряется только обратное значение из-за даты (до 30D в обратном направлении). Есть ли способ реализовать это в SQL или я требую слишком много?

Ответы [ 2 ]

0 голосов
/ 22 сентября 2018

Ниже для BigQuery Standard SQL

#standardSQL
SELECT *,
  AVG(score) OVER (
    PARTITION BY user 
    ORDER BY UNIX_DATE(PARSE_DATE('%d/%m/%Y', date))
    RANGE BETWEEN 29 PRECEDING AND CURRENT ROW
  ) AS avg_30day 
FROM `project.dataset.scores` 

Вы можете протестировать / поиграть с использованием вышеупомянутых фиктивных данных из вашего вопроса

#standardSQL
WITH `project.dataset.scores` AS (
  SELECT 'AA' user, '13/02/2018' date, 2.00 score UNION ALL
  SELECT 'AA', '15/02/2018', 3.00 UNION ALL
  SELECT 'AA', '17/02/2018', 4.00 UNION ALL
  SELECT 'AA', '01/03/2018', 5.00 UNION ALL
  SELECT 'AA', '28/03/2018', 6.00 
)
SELECT *,
  AVG(score) OVER (
    PARTITION BY user 
    ORDER BY UNIX_DATE(PARSE_DATE('%d/%m/%Y', date))
    RANGE BETWEEN 29 PRECEDING AND CURRENT ROW
  ) AS avg_30day 
FROM `project.dataset.scores` 

результат

Row user    date        score   avg_30day    
1   AA      13/02/2018  2.0     2.0  
2   AA      15/02/2018  3.0     2.5  
3   AA      17/02/2018  4.0     3.0  
4   AA      01/03/2018  5.0     3.5  
5   AA      28/03/2018  6.0     5.5  
0 голосов
/ 22 сентября 2018

Вы хотите использовать range between.Для этого вам нужно целое число, поэтому:

select s.*,
       avg(score) over (partition by user
                        order by days
                        range between 29 preceding and current row
                       ) as avg_30day
from (select s.*, date_diff(s.date, date('2000-01-01'), day) as days
      from scores s
     ) s;

Альтернативой date_diff() является unix_date():

select s.*,
       avg(score) over (partition by user
                        order by unix_days
                        range between 29 preceding and current row
                       ) as avg_30day
from (select s.*, unix_date(s.date) as unix_days
      from scores s
     ) s;
...