Подсчитайте количество типов действий для пользователя перед определенным действием в BigQuery - PullRequest
0 голосов
/ 19 сентября 2019

У меня есть таблица с журналом действий, выполненных пользователем, типы действий - создание, подтверждение и отмена, что-то вроде этого:

action   datetime              user
create   2019-01-01 10:00:00   A
create   2019-01-05 10:00:00   A
confirm  2019-01-07 10:00:00   A
create   2019-01-07 10:00:00   A
cancel   2019-01-08 10:00:00   A
create   2019-01-09 10:00:00   A
create   2019-01-03 10:00:00   B
cancel   2019-01-08 10:00:00   B
create   2019-01-12 10:00:00   B

Итак, я хотел бы получить числодействия по типу, которые были сделаны пользователем перед созданием каждого действия, поэтому для данных до результата было бы так:

action   datetime              user  create  confirm  cancel
create   2019-01-01 10:00:00   A     0       0        0
create   2019-01-05 10:00:00   A     1       0        0
create   2019-01-07 10:00:00   A     2       1        0
create   2019-01-09 10:00:00   A     3       1        1
create   2019-01-03 10:00:00   B     0       0        0
create   2019-01-12 10:00:00   B     1       0        1

я пытался настроить решение для this , но не могу получить различное количество по типу действия.

SELECT * FROM 
  ( select *, count(1) OVER(PARTITION BY action, user ORDER BY datetime ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) create from `table` ) 
  WHERE action = 'create' ORDER BY datetime LIMIT 20;

Есть идеи?

ОБНОВЛЕНИЕ: наконец получено 2 запроса,

Запрос 1:

select *
from (select t.*,  
             countif(action = 'create') over (PARTITION BY user order by datetime rows between unbounded preceding and 1 preceding) as num_create,
             countif(action = 'confirm') over (PARTITION BY user order by datetime rows between unbounded preceding and 1 preceding) as num_confirm,
             countif(action = 'cancel') over (PARTITION BY user order by datetime rows between unbounded preceding and 1 preceding) as num_cancel
      from t
     ) t
where action = 'create' order by datetime;

Запрос 2:

select *
from (select t.*, 
             countif(action = 'create') over (PARTITION BY user order by datetime_diff(datetime(datetime), datetime('2000-01-01'), SECOND) range between unbounded preceding and 1 preceding) as num_create,
             countif(action = 'confirm') over (PARTITION BY user order by datetime_diff(datetime(datetime), datetime('2000-01-01'), SECOND) range between unbounded preceding and 1 preceding) as num_confirm,
             countif(action = 'cancel') over (PARTITION BY user order by datetime_diff(datetime(datetime), datetime('2000-01-01'), SECOND) range between unbounded preceding and 1 preceding) as num_cancel
      from t
     ) t
where action = 'create' order by datetime;

Когда пользователь выполняет более 1 действия одновременно, Запрос 1 работает лучше.Спасибо !!

ОБНОВЛЕНИЕ 2: Окончательный запрос

#standardSQL
SELECT * FROM (
  SELECT action, datetime, user, 
    COUNTIF(action = 'create') OVER(win) `create`,
    COUNTIF(action = 'confirm') OVER(win) confirm,
    COUNTIF(action = 'cancel') OVER(win) cancel
  FROM `project.dataset.table`
  WINDOW win AS (
    PARTITION BY user 
    ORDER BY datetime, CASE action WHEN 'create' THEN 1 ELSE 0 END 
    ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
  ) 
)
WHERE action = 'create'
ORDER BY user, datetime

Ответы [ 2 ]

1 голос
/ 19 сентября 2019

Ниже для BigQuery Standard SQL

#standardSQL
SELECT * FROM (
  SELECT action, datetime, user, 
    COUNTIF(action = 'create') OVER(win) `create`,
    COUNTIF(action = 'confirm') OVER(win) confirm,
    COUNTIF(action = 'cancel') OVER(win) cancel
  FROM `project.dataset.table`
  WINDOW win AS (
    PARTITION BY user 
    ORDER BY datetime, CASE action WHEN 'create' THEN 1 ELSE 0 END 
    ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
  ) 
)
WHERE action = 'create'
ORDER BY user, datetime

, если применить к образцу данных из вашего вопроса - результат

Row action  datetime                user    create  confirm cancel   
1   create  2019-01-01T10:00:00     A       0       0       0    
2   create  2019-01-05T10:00:00     A       1       0       0    
3   create  2019-01-07T10:00:00     A       2       1       0    
4   create  2019-01-09T10:00:00     A       3       1       1    
5   create  2019-01-03T10:00:00     B       0       0       0    
6   create  2019-01-12T10:00:00     B       1       0       1      

Примечание: здесь решена "проблема" с повторяющимися датамииспользуя CASE action WHEN 'create' THEN 1 ELSE 0 END в порядке по выражению окна.

1 голос
/ 19 сентября 2019

Похоже, вам нужны кумулятивные суммы и фильтрация:

select *
from (select t.*,
             countif(action = 'create') over (order by datetime rows between unbounded preceding and 1 preceding) as num_create,
             countif(action = 'confirm') over (order by datetime rows between unbounded preceding and 1 preceding) as num_confirm,
             countif(action = 'cancel') over (order by datetime rows between unbounded preceding and 1 preceding) as num_cancel
      from t
     ) t
where action = 'create';

На самом деле ваши времена имеют дублирующиеся значения, что может быть немного сложнее.Я бы порекомендовал вам изменить проблему, чтобы включить текущий период времени.Но если вам действительно нужно «до», вы можете использовать range.К сожалению, interval недопустимо, поэтому необходимо преобразовать критерий порядка в число:

select *
from (select t.*,
             countif(action = 'create') over (order by datetime_diff(second, datetime('2000-01-01'), datetime) range between unbounded preceding and 1 preceding) as num_create,
             countif(action = 'confirm') over (order by datetime_diff(second, datetime('2000-01-01'), datetime) range between unbounded preceding and 1 preceding) as num_confirm,
             countif(action = 'cancel') over (order by datetime_diff(second, datetime('2000-01-01'), datetime) range between unbounded preceding and 1 preceding) as num_cancel
      from t
     ) t
where action = 'create';
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...