Указание непредвиденных обстоятельств для функции max (date) в запросе Redshift - PullRequest
0 голосов
/ 13 апреля 2019

Я пытаюсь определить, когда клиенты не входят в систему в течение календарной недели, когда в последний раз они входили в систему. Начальный набор данных выглядит примерно так:

User_Name   Login_Date  Week_Ending
Bobisaur    1/1/2019    1/5/2019
Bobisaur    1/3/2019    1/5/2019
Bobisaur    3/5/2019    3/9/2019
Bobisaur    3/24/2019   3/30/2019
Bobisaur    4/1/2019    4/6/2019

Теперь для недели, заканчивающейся 1/12/2019 и т. Д., Для клиента не будет входов Bobisaur Я хотел бы получить набор данных, который выглядит следующим образом:

User_Name   Week_Ending (for weeks with no login)   Days Since Last Login (as of week ending date)
Bobisaur    1/12/2019    7 
Bobisaur    1/19/2019    14 
Bobisaur    1/26/2019    21 
Bobisaur    2/2/2019     28 
Bobisaur    2/9/2019     35 
Bobisaur    2/16/2019    42 
Bobisaur    2/23/2019    49 
Bobisaur    3/2/2019     56 
Bobisaur    3/16/2019    11 
Bobisaur    3/23/2019    18 
Bobisaur    4/13/2019    12 

Это будет фильтрация по списку недель для пользователя, для которого у него не было логина, и столбца для количества дней, прошедших с момента последнего входа в систему, на эту конкретную дату окончания недели.

Я могу получить Week_Ending даты, когда нет активности входа в систему, однако я застрял при расчете «Дней с момента последнего входа в систему (по состоянию на дату окончания недели)». Я попытался использовать (Week_Ending - max(Login_Date)), а затем указать предложение, имеющее max(Login_Date) <= Week_Ending.

Однако это в основном убрало все строки, где значение Week_Ending было ранее, чем максимальное Login_Date.

Любая помощь будет принята с благодарностью. Спасибо!

1 Ответ

0 голосов
/ 16 апреля 2019

Результирующий запрос кажется сложным, но он не так плох:

  • intput_raw - все, что вы вставили в вопрос
  • input - поменялся местами login_data с соответствующимиweek_ending
  • cal - календарная таблица с последовательными субботами (ваше определение неделя, заканчивающаяся ).В Redshift единственный способ генерировать строк - это SELECT.Здесь я генерирую 25 строк путем перекрестного соединения ввода с самим собой, чтобы получить 25 (5x5) последовательных суббот.CROSS JOIN можно изменить на SELECT row_number() over () from arbitrary table limit 25.
  • cal_usrs - таблица со всеми пользователями и всеми субботами
  • output_raw - сердце расчета - сначала JOIN cal_usrs с input и использовать оконную функцию, чтобы получить дней с момента последнего входа в систему .Поскольку невозможно фильтровать столбец с помощью результата оконной функции (а желаемый вывод не содержит строк с 0), в конечном итоге получается SELECT.
  • final SELECT - выбирает только то, что нас интересует.

Запрос:

with input_raw as (
  select 'Bobisaur' as username, '1/1/2019'::date as login_date
  union all
  select 'Bobisaur', '1/3/2019'::date
  union all
  select 'Bobisaur', '3/5/2019'::date
  union all
  select 'Bobisaur', '3/24/2019'::date
  union all
  select 'Bobisaur', '4/1/2019'::date
), input as (
  select
         username,
         -- in your example weeks ends on saturday hence Monday + 5 days
         date_trunc('week', login_date) + interval '5 days' as week_ending
  from input_raw
), cal as (
  -- this will create a table with consecutive Saturdays
  select
         date_trunc('week', '12/1/2018'::date) + interval '5 days'+ 7 * row_number() over () as week_ending
  -- can be changed to 'from arbitrary table limit 25' or whatever time window you wish
  from input_raw a cross join input_raw b --this will produce 25 rows

), cal_usrs as (
  select * from cal cross join (select distinct username from input) as u
  -- this is very important - you want to have all weeks with all users
), output_raw as (
  select cal_usrs.username,
         cal_usrs.week_ending,
         max(input.week_ending)
             over (partition by cal_usrs.username order by cal_usrs.week_ending rows between unbounded preceding and current row ) as last_login_week,
         extract('days' from cal_usrs.week_ending - last_login_week) as days_since_last_login
  from input
         right join cal_usrs using (username, week_ending)
)
select
  username,
  to_char(week_ending, 'MM/DD/YYYY') as week_anding,
  days_since_last_login
from output_raw
where days_since_last_login <> 0 -- your example did not contain 0 rows
order by week_ending

результат выглядиткак (я думаю, что вы сделали какой-то просчет в своем примере после 16 марта):

    username    week_ending days_since_last_login
    Bobisaur    01/12/2019  7
    Bobisaur    01/19/2019  14
    Bobisaur    01/26/2019  21
    Bobisaur    02/02/2019  28
    Bobisaur    02/09/2019  35
    Bobisaur    02/16/2019  42
    Bobisaur    02/23/2019  49
    Bobisaur    03/02/2019  56
    Bobisaur    03/16/2019  7
    Bobisaur    03/30/2019  7
    Bobisaur    04/13/2019  7
    Bobisaur    04/20/2019  14
    Bobisaur    04/27/2019  21
    Bobisaur    05/04/2019  28
    Bobisaur    05/11/2019  35
    Bobisaur    05/18/2019  42
    Bobisaur    05/25/2019  49
...