Как посчитать (не) последовательные записи по дням в bigquery? - PullRequest
0 голосов
/ 26 марта 2019

Каждая неисправность устройства регистрируется. Каждая запись содержит идентификатор клиента, идентификатор устройства и отметку времени:

+-------------+-----------+-----------------------+
| customer_id | device_id |  timestamp            |
+-------------+-----------+-----------------------+
| 1           | 1         |  2019-02-12T01:00:00  |
| 2           | 2         |  2019-02-12T01:00:00  |
| 1           | 1         |  2019-02-12T02:00:00  |
| 1           | 1         |  2019-02-12T03:00:00  |
+-------------+-----------+-----------------------+

Журналы неисправностей собираются каждый час. Я заинтересован в следующей информации:

  • общее количество неисправностей на одного клиента в день
  • количество последовательных неисправностей на одного клиента в день
  • количество непоследовательных неисправностей на одного клиента в день

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

Результат должен выглядеть следующим образом:

+-------------+-----------+---------------------+-----------------+------------+-----------------------+
| customer_id | device_id | total | consecutive | non consecutive |  day       | last_recording        |
+-----+-------------------+-------+-------------+-----------------+------------------------------------+
| 1           | 1         | 3     |  1          | 2               | 2019-02-12 |  2019-02-12T03:00:00  |
| 2           | 2         | 1     |  0          | 1               | 2019-02-12 |  2019-02-12T01:00:00  |
+-------------+-----------+-------+-------------+-----------------+------------+-----------------------+

В приведенном выше примере устройство 1 сообщило о сбое в 2019-02-12T02: 00: 00, которое считается «непоследовательным», и сразу после этого другое в 2019-02-12T03: 00: 00, которое считается « подряд».

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

SELECT customer_id, device_id, COUNT(customer_id) AS count, FORMAT_TIMESTAMP("%Y-%m-%d", TIMESTAMP(timestamp)) as day
FROM `malfunctions`
GROUP BY day, customer_id, device_id

Таким образом, я могу узнать общее количество неисправностей по дням. Я думаю, что я должен использовать оператор LEAD, чтобы получить (не) последовательный счет, но я не уверен, как. Есть идеи? Результаты должны «катиться» по дням.

1 Ответ

1 голос
/ 26 марта 2019

Ниже для BigQuery Standard SQL

#standardSQL
SELECT customer_id, device_id, day, SUM(batch_count) total, 
  SUM(batch_count) - COUNTIF(batch_count = 1) consecutive,
  COUNTIF(batch_count = 1) non_consecutive, 
  ARRAY_AGG(STRUCT(batch AS batch, batch_count AS batch_count, first_recording AS first_recording, last_recording AS last_recording)) details
FROM (
  SELECT customer_id, device_id, day, batch, 
    COUNT(1) batch_count,
    MIN(ts) first_recording,
    MAX(ts) last_recording
  FROM (
    SELECT customer_id, device_id, ts, day,
      COUNTIF(gap) OVER(PARTITION BY customer_id, device_id, day ORDER BY  ts) batch
    FROM (
      SELECT customer_id, device_id, ts, DATE(ts) day,
        IFNULL(TIMESTAMP_DIFF(ts, LAG(ts) OVER(PARTITION BY customer_id, device_id, DATE(ts) ORDER BY  ts), HOUR), 777) > 1 gap
      FROM `project.dataset.malfunctions`
    )
  )
  GROUP BY customer_id, device_id, day, batch
)
GROUP BY customer_id, device_id, day

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

#standardSQL
WITH `project.dataset.malfunctions` AS (
  SELECT 1 customer_id, 1 device_id, TIMESTAMP '2019-02-12T01:00:00' ts UNION ALL
  SELECT 1, 1, '2019-02-12T02:00:00' UNION ALL
  SELECT 1, 1, '2019-02-12T03:00:00' UNION ALL
  SELECT 1, 1, '2019-02-12T04:00:00' UNION ALL
  SELECT 1, 1, '2019-02-12T09:00:00' UNION ALL
  SELECT 1, 1, '2019-02-12T10:00:00' UNION ALL
  SELECT 1, 1, '2019-02-13T03:00:00' UNION ALL
  SELECT 2, 2, '2019-02-12T01:00:00' 
)
SELECT customer_id, device_id, day, SUM(batch_count) total, 
  SUM(batch_count) - COUNTIF(batch_count = 1) consecutive,
  COUNTIF(batch_count = 1) non_consecutive, 
  ARRAY_AGG(STRUCT(batch AS batch, batch_count AS batch_count, first_recording AS first_recording, last_recording AS last_recording)) details
FROM (
  SELECT customer_id, device_id, day, batch, 
    COUNT(1) batch_count,
    MIN(ts) first_recording,
    MAX(ts) last_recording
  FROM (
    SELECT customer_id, device_id, ts, day,
      COUNTIF(gap) OVER(PARTITION BY customer_id, device_id, day ORDER BY  ts) batch
    FROM (
      SELECT customer_id, device_id, ts, DATE(ts) day,
        IFNULL(TIMESTAMP_DIFF(ts, LAG(ts) OVER(PARTITION BY customer_id, device_id, DATE(ts) ORDER BY  ts), HOUR), 777) > 1 gap
      FROM `project.dataset.malfunctions`
    )
  )
  GROUP BY customer_id, device_id, day, batch
)
GROUP BY customer_id, device_id, day
-- ORDER BY customer_id, device_id, day

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

enter image description here

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