Сглаживание таблицы событий в SQL BigQuery - PullRequest
0 голосов
/ 31 августа 2018

У меня есть таблица events, которая содержит 3 типа событий для каждой кампании и человека. 3 события: «Полученная электронная почта», «Открытое электронное письмо» и «Кликаемое электронное письмо» Я хочу получить метку времени каждого события для человека / кампании в виде нового столбца в таблице. Какой лучший способ сделать это?

Пример таблицы данных:

campaign_id     person_id     event_type     timestamp

1               1             Received Email 2018-01-01
1               1             Opened Email   2018-02-01
1               1             Clicked Email  2018-03-01
1               2             Received Email 2018-01-01
1               2             Opened Email   2018-02-01
1               2             Opened Email   2018-02-02

Пример вывода:

    campaign_id     person_id     event_type     timestamp     receive_ts     open_ts     click_ts

    1               1             Received Email 2018-01-01    2018-01-01     2018-02-01  2018-03-01
    1               1             Opened Email   2018-02-01    2018-01-01     2018-02-01  2018-03-01
    1               1             Clicked Email  2018-03-01    2018-01-01     2018-02-01  2018-03-01
    1               2             Received Email 2018-01-01    2018-01-01     2018-02-01
    1               2             Opened Email   2018-02-01    2018-01-01     2018-02-01
    1               2             Opened Email   2018-02-02    2018-01-01     2018-02-01

Единственное решение, которое мне приходит в голову, - это присоединить таблицу к себе 3 раза по campaign_id и person_id, по одному разу для каждого типа события, но таблица содержит более 400 м строк, так что это, очевидно, будет неэффективным.

Любые предложения приветствуются!

Ответы [ 2 ]

0 голосов
/ 31 августа 2018

Ниже для BigQuery Standard SQL и нет - вам не нужно делать три СОЕДИНЕНИЯ - вам даже не нужны здесь СОЕДИНЕНИЯ

#standardSQL
SELECT campaign_id, person_id, event_type, ts,
  FIRST_VALUE(IF(event_type='Received Email', ts, NULL) IGNORE NULLS) OVER(win) receive_ts,
  FIRST_VALUE(IF(event_type='Opened Email', ts, NULL) IGNORE NULLS) OVER(win) open_ts,
  FIRST_VALUE(IF(event_type='Clicked Email', ts, NULL) IGNORE NULLS) OVER(win) click_ts
FROM `project.dataset.table`
WINDOW win AS (PARTITION BY campaign_id, person_id ORDER BY ts ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)

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

#standardSQL
WITH `project.dataset.table` AS (
  SELECT 1 campaign_id, 1 person_id, 'Received Email' event_type, '2018-01-01' ts UNION ALL
  SELECT 1, 1, 'Opened Email', '2018-02-01' UNION ALL
  SELECT 1, 1, 'Clicked Email', '2018-03-01' UNION ALL
  SELECT 1, 2, 'Received Email', '2018-01-01' UNION ALL
  SELECT 1, 2, 'Opened Email', '2018-02-01' UNION ALL
  SELECT 1, 2, 'Opened Email', '2018-02-02' 
)
SELECT campaign_id, person_id, event_type, ts,
  FIRST_VALUE(IF(event_type='Received Email', ts, NULL) IGNORE NULLS) OVER(win) receive_ts,
  FIRST_VALUE(IF(event_type='Opened Email', ts, NULL) IGNORE NULLS) OVER(win) open_ts,
  FIRST_VALUE(IF(event_type='Clicked Email', ts, NULL) IGNORE NULLS) OVER(win) click_ts
FROM `project.dataset.table`
WINDOW win AS (PARTITION BY campaign_id, person_id ORDER BY ts ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
-- ORDER BY campaign_id, person_id, ts   

результат должен быть

Row campaign_id person_id   event_type      ts          receive_ts  open_ts     click_ts     
1   1           1           Received Email  2018-01-01  2018-01-01  2018-02-01  2018-03-01   
2   1           1           Opened Email    2018-02-01  2018-01-01  2018-02-01  2018-03-01   
3   1           1           Clicked Email   2018-03-01  2018-01-01  2018-02-01  2018-03-01   
4   1           2           Received Email  2018-01-01  2018-01-01  2018-02-01  null     
5   1           2           Opened Email    2018-02-01  2018-01-01  2018-02-01  null     
6   1           2           Opened Email    2018-02-02  2018-01-01  2018-02-01  null     
0 голосов
/ 31 августа 2018

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

SELECT
    campaign_id,
    person_id,
    TIMESTAMP_DIFF(
        MAX(CASE WHEN event_type = 'Opened Email' THEN timestamp END),
        MAX(CASE WHEN event_type = 'Received Email' THEN timestamp END),
        MINUTE) AS diff_in_minutes
FROM yourTable
GROUP BY
    campaign_id,
    person_id;

Примечание. Этот ответ был дан на первоначальный вопрос, который впоследствии был существенно изменен.

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