SQL-запрос для установки столбца на основе последних семи записей - PullRequest
0 голосов
/ 11 сентября 2018

Задача

У меня возникают проблемы с выяснением, как создать запрос, который может определить, предшествует ли какой-либо userrentry 7 дней без какой-либо активности (secondsPlayed == 0), и если да, то укажите его со значением 1, в противном случае 0.

Это также означает, что если у пользователя менее 7 записей, значение будет равно 0 для всех записей.


Input table:
+------------------------------+-------------------------+---------------+
|            userid            |     estimationDate      | secondsPlayed |
+------------------------------+-------------------------+---------------+
| a                            | 2016-07-14 00:00:00 UTC | 192.5         |
| a                            | 2016-07-15 00:00:00 UTC | 357.3         |
| a                            | 2016-07-16 00:00:00 UTC | 0             |
| a                            | 2016-07-17 00:00:00 UTC | 0             |
| a                            | 2016-07-18 00:00:00 UTC | 0             |
| a                            | 2016-07-19 00:00:00 UTC | 0             |
| a                            | 2016-07-20 00:00:00 UTC | 0             |
| a                            | 2016-07-21 00:00:00 UTC | 0             |
| a                            | 2016-07-22 00:00:00 UTC | 0             |
| a                            | 2016-07-23 00:00:00 UTC | 0             |
| a                            | 2016-07-24 00:00:00 UTC | 0             |
| ---------------------------- | ----------------------  | ----          |
| b                            | 2016-07-02 00:00:00 UTC | 31.2          |
| b                            | 2016-07-03 00:00:00 UTC | 42.1          |
| b                            | 2016-07-04 00:00:00 UTC | 41.9          |
| b                            | 2016-07-05 00:00:00 UTC | 43.2          |
| b                            | 2016-07-06 00:00:00 UTC | 91.5          |
| b                            | 2016-07-07 00:00:00 UTC | 0             |
| b                            | 2016-07-08 00:00:00 UTC | 0             |
| b                            | 2016-07-09 00:00:00 UTC | 239.1         |
| b                            | 2016-07-10 00:00:00 UTC | 0             |
+------------------------------+-------------------------+---------------+

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


Output table:

+------------------------------+-------------------------+---------------+----------+
|            userid            |     estimationDate      | secondsPlayed | inactive |
+------------------------------+-------------------------+---------------+----------+
| a                            | 2016-07-14 00:00:00 UTC | 192.5         | 0        |
| a                            | 2016-07-15 00:00:00 UTC | 357.3         | 0        |
| a                            | 2016-07-16 00:00:00 UTC | 0             | 0        |
| a                            | 2016-07-17 00:00:00 UTC | 0             | 0        |
| a                            | 2016-07-18 00:00:00 UTC | 0             | 0        |
| a                            | 2016-07-19 00:00:00 UTC | 0             | 0        |
| a                            | 2016-07-20 00:00:00 UTC | 0             | 0        |
| a                            | 2016-07-21 00:00:00 UTC | 0             | 0        |
| a                            | 2016-07-22 00:00:00 UTC | 0             | 1        |
| a                            | 2016-07-23 00:00:00 UTC | 0             | 1        |
| a                            | 2016-07-24 00:00:00 UTC | 0             | 1        |
| ---------------------------- | ----------------------- | -----         | -----    |
| b                            | 2016-07-02 00:00:00 UTC | 31.2          | 0        |
| b                            | 2016-07-03 00:00:00 UTC | 42.1          | 0        |
| b                            | 2016-07-04 00:00:00 UTC | 41.9          | 0        |
| b                            | 2016-07-05 00:00:00 UTC | 43.2          | 0        |
| b                            | 2016-07-06 00:00:00 UTC | 91.5          | 0        |
| b                            | 2016-07-07 00:00:00 UTC | 0             | 0        |
| b                            | 2016-07-08 00:00:00 UTC | 0             | 0        |
| b                            | 2016-07-09 00:00:00 UTC | 239.1         | 0        |
| b                            | 2016-07-10 00:00:00 UTC | 0             | 0        |
+------------------------------+-------------------------+---------------+----------+


Мысли

Сначала я думал об использовании функции запаздывания со смещением 7, но это, очевидно, не относится ни к одному из объектов между ними.

Я также думал о создании скользящего окна / среднего для периода в 7 дней и оценке, если это выше 0. Однако это может быть немного выше моего уровня квалификации.

Любой шанс, что у кого-то есть хорошее решение этой проблемы.

Ответы [ 2 ]

0 голосов
/ 11 сентября 2018

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


Input table:
+------------------------------+-------------------------+---------------+
|            userid            |     estimationDate      | secondsPlayed |
+------------------------------+-------------------------+---------------+
| a                            | 2016-07-14 00:00:00 UTC | 192.5         |
| a                            | 2016-07-15 00:00:00 UTC | 357.3         |
| ---------------------------- | ----------------------  | ----          |
| b                            | 2016-07-02 00:00:00 UTC | 31.2          |
| b                            | 2016-07-03 00:00:00 UTC | 42.1          |
| b                            | 2016-07-04 00:00:00 UTC | 41.9          |
| b                            | 2016-07-05 00:00:00 UTC | 43.2          |
| b                            | 2016-07-06 00:00:00 UTC | 91.5          |
| b                            | 2016-07-09 00:00:00 UTC | 239.1         |
+------------------------------+-------------------------+---------------+

Итак, ниже приведен стандарт SQL для BigQuery и ввод в видевыше

#standardSQL
WITH `project.dataset.table` AS (
  SELECT 'a' userid, TIMESTAMP '2016-07-14 00:00:00 UTC' estimationDate, 192.5 secondsPlayed UNION ALL
  SELECT 'a', '2016-07-15 00:00:00 UTC', 357.3 UNION ALL
  SELECT 'b', '2016-07-02 00:00:00 UTC', 31.2 UNION ALL
  SELECT 'b', '2016-07-03 00:00:00 UTC', 42.1 UNION ALL
  SELECT 'b', '2016-07-04 00:00:00 UTC', 41.9 UNION ALL
  SELECT 'b', '2016-07-05 00:00:00 UTC', 43.2 UNION ALL
  SELECT 'b', '2016-07-06 00:00:00 UTC', 91.5 UNION ALL
  SELECT 'b', '2016-07-09 00:00:00 UTC', 239.1 
), time_frame AS (
  SELECT day
  FROM UNNEST(GENERATE_DATE_ARRAY('2016-07-02', '2016-07-24')) day
)
SELECT 
  users.userid, 
  day, 
  IFNULL(secondsPlayed, 0) secondsPlayed,
  CAST(1 - SIGN(SUM(IFNULL(secondsPlayed, 0)) 
    OVER(
      PARTITION BY users.userid 
      ORDER BY UNIX_DATE(day)
      RANGE BETWEEN 6 PRECEDING AND CURRENT ROW
    )) AS INT64) AS inactive 
FROM time_frame tf
CROSS JOIN (SELECT DISTINCT userid FROM `project.dataset.table`) users
LEFT JOIN `project.dataset.table` t
ON day = DATE(estimationDate) AND users.userid = t.userid
ORDER BY userid, day   

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

Row userid  day         secondsPlayed   inactive     
...
13  a       2016-07-14  192.5           0    
14  a       2016-07-15  357.3           0    
15  a       2016-07-15  357.3           0    
16  a       2016-07-16  0.0             0    
17  a       2016-07-17  0.0             0    
18  a       2016-07-18  0.0             0    
19  a       2016-07-19  0.0             0    
20  a       2016-07-20  0.0             0    
21  a       2016-07-21  0.0             0    
22  a       2016-07-22  0.0             1    
23  a       2016-07-23  0.0             1    
24  a       2016-07-24  0.0             1    
25  b       2016-07-02  31.2            0    
26  b       2016-07-03  42.1            0    
27  b       2016-07-04  41.9            0    
28  b       2016-07-05  43.2            0    
29  b       2016-07-06  91.5            0    
30  b       2016-07-07  0.0             0    
31  b       2016-07-08  0.0             0    
32  b       2016-07-09  239.1           0    
33  b       2016-07-10  0.0             0    
...  

0 голосов
/ 11 сентября 2018

Предполагая, что у вас есть данные каждый день (что кажется разумным предположением), вы можете суммировать оконную функцию:

select t.*,
       (case when sum(secondsplayed) over (partition by userid
                                           order by estimationdate
                                           rows between 6 preceding and current row
                                          ) = 0 and
                  row_number() over (partition by userid order by estimationdate) >= 7
             then 1
             else 0
        end) as inactive                  
from t;

В дополнение к отсутствию дырок в датах, это также предполагает, что secondsplayed никогда не бывает отрицательным.(Отрицательные значения могут быть легко включены в логику, но это кажется ненужным.)

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