Запрос, чтобы найти записи, которые были созданы один за другим в BigQuery - PullRequest
0 голосов
/ 01 марта 2019

Я играю с большим запросом.Введены следующие данные:

+---------------+---------+---------+--------+----------------------+
|   customer    |  agent  |  value  |  city  |   timestamp          |
+---------------+---------+---------+--------+----------------------+
| 1             | 1       |  106    | LA     |  2019-02-12 03:05pm  |
| 1             | 1       |  251    | LA     |  2019-02-12 03:06pm  |
| 3             | 2       |  309    | NY     |  2019-02-12 06:41pm  |
| 1             | 1       |  654    | LA     |  2019-02-12 05:12pm  |
+---------------+---------+---------+--------+----------------------+

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

+---------------+---------+---------+--------+----------------------+
|   customer    |  agent  |  value  |  city  |   timestamp          |
+---------------+---------+---------+--------+----------------------+
| 1             | 1       |  106    | LA     |  2019-02-12 03:05pm  |
| 1             | 1       |  251    | LA     |  2019-02-12 03:06pm  |
+---------------+---------+---------+--------+----------------------+

Запрос должен каким-то образом группироваться по агенту и находить такие транзакции.Однако результат на самом деле не сгруппирован, как вы можете видеть из результатов.Моей первой мыслью было использование функции LEAD, но я не уверен.У вас есть идеи?

Идеи для запроса:

  • сортировка по агенту и метке времени DESC
  • начать с первой строки, посмотрите на следующую строку (используя LEAD?)
  • проверить, если разница меток времени меньше 5 минут
  • , если это так, эти две строки должны быть в выходных данных
  • продолжить со следующей (2-й) строкой

Когда 2-й и 3-й ряды также соответствуют критериям, 2-й ряд попадет в вывод, что приведет к дублированию строк.Я пока не знаю, как этого избежать.

Ответы [ 2 ]

0 голосов
/ 01 марта 2019

Ниже для BigQuery Standard SQL

#standardSQL
SELECT * FROM (
  SELECT *, 
    IF(TIMESTAMP_DIFF(LEAD(ts) OVER(PARTITION BY agent ORDER BY ts), ts, MINUTE) < 5, 
      LEAD(STRUCT(customer AS next_customer, value AS next_value)) OVER(PARTITION BY agent ORDER BY ts), 
    NULL).* 
  FROM `project.dataset.yourtable`
)
WHERE NOT next_customer IS NULL

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

#standardSQL
WITH `project.dataset.table` AS (
  SELECT 1 customer, 1 agent, 106 value,'LA' city, '2019-02-12 03:05pm' ts UNION ALL
  SELECT 1, 1, 251,'LA', '2019-02-12 03:06pm' UNION ALL
  SELECT 3, 2, 309,'NY', '2019-02-12 06:41pm' UNION ALL
  SELECT 1, 1, 654,'LA', '2019-02-12 05:12pm' 
), temp AS (
  SELECT customer, agent, value, city, PARSE_TIMESTAMP('%Y-%m-%d %I:%M%p', ts) ts 
  FROM `project.dataset.table`
)
SELECT * FROM (
  SELECT *, 
    IF(TIMESTAMP_DIFF(LEAD(ts) OVER(PARTITION BY agent ORDER BY ts), ts, MINUTE) < 5, 
      LEAD(STRUCT(customer AS next_customer, value AS next_value)) OVER(PARTITION BY agent ORDER BY ts), 
    NULL).* 
  FROM temp
)
WHERE NOT next_customer IS NULL
-- ORDER BY ts

с результатом

Row customer    agent   value   city    ts                      next_customer   next_value   
1   1           1       106     LA      2019-02-12 15:05:00 UTC 1               251  
0 голосов
/ 01 марта 2019

Должен быть более простой путь, но достигает ли он того, что вы ищете?

CTE2 AS (
SELECT customer, agent, value, city, timestamp,
  lead(timestamp,1) OVER (PARTITION BY agent ORDER BY timestamp) timestamp_lead,
  lead(customer,1) OVER (PARTITION BY agent ORDER BY timestamp) customer_lead,
  lead(value,1) OVER (PARTITION BY agent ORDER BY timestamp) value_lead,
  lead(city,1) OVER (PARTITION BY agent ORDER BY timestamp) city_lead,
  lag(timestamp,1) OVER (PARTITION BY agent ORDER BY timestamp) timestamp_lag
FROM CTE
)

SELECT agent, 
  if(timestamp_diff(timestamp_lead,timestamp,MINUTE)<5, concat(cast(customer as string),', ',cast(customer_lead as string)),cast(customer as string)) customer, 
  if(timestamp_diff(timestamp_lead,timestamp,MINUTE)<5, concat(cast(value as string),', ',cast(value_lead as string)),cast(value as string)) value,
  if(timestamp_diff(timestamp_lead,timestamp,MINUTE)<5, concat(cast(city as string),', ',cast(city_lead as string)),cast(city as string)) cities,
  if(timestamp_diff(timestamp_lead,timestamp,MINUTE)<5, concat(cast(timestamp as string),', ',cast(timestamp_lead as string)),cast(timestamp as string)) timestamps
FROM CTE2
WHERE (timestamp_diff(timestamp_lead,timestamp,MINUTE)<5 OR NOT timestamp_diff(timestamp,timestamp_lag,MINUTE)<5)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...