Нахождение самой последней вещи до определенного события - PullRequest
0 голосов
/ 20 декабря 2018

Я решаю некоторые проблемы с отметками времени, но застрял в некоторой логике соединения.

У меня есть таблица данных, подобная этой:

id, event_time, event_type, location
1001, 2018-06-04 18:23:48.526895 UTC, I, d
1001, 2018-06-04 19:26:44.359296 UTC, I, h
1001, 2018-06-05 06:07:03.658263 UTC, I, w
1001, 2018-06-07 00:47:44.651841 UTC, I, d
1001, 2018-06-07 00:48:17.857729 UTC, C, d
1001, 2018-06-08 00:04:53.086240 UTC, I, a
1001, 2018-06-12 21:23:03.071829 UTC, I, d
...

И я пытаюсь найтиразница во времени между тем, когда пользователь имеет тип события C, и самым последним типом события от I до события_тип C для данного значения местоположения.

В конечном счете схема, которую я ищу, это:

id, location, timestamp_diff
1001, d, 33
1001, z, 21
1002, a, 55
...

Я попробовал следующее, которое работает только для одного значения id, но, похоже, не работает для кратных id с.Возможно, я слишком усложняю проблему, но я не был уверен.На одном id это дает около 5 строк, что верно.Однако, когда я открываю его на два id с, я получаю более 200 строк, когда мне нужно что-то вроде 7 (5 для первого id и 2 для второго):

with c as (
select 
id
,event_time as c_time
,location
from data
where event_type = 'C'
and id = '1001'
)

,i as (
select 
id
,event_time as i_time
,location
from data
where event_type = 'I'
)

,check1 as (
c.*
,i.i_time
from c
left join i on (c.id = i.id and c.location = i.location)
group by 1,2,3,4
having i_time <= c_time
)

,check2 as (
select
id
,c_time
,location
,max(i_time) as i_time
from check1
group by 1,2,3
)

select
id
,location
,timestamp_diff(c_time, i_time, second) as timestamp_diff

Ответы [ 2 ]

0 голосов
/ 20 декабря 2018
#standardSQL
SELECT id, location, TIMESTAMP_DIFF(event_time, i_event_time, SECOND) AS diff
FROM (
  SELECT *, MAX(IF(event_type = 'I', event_time, NULL)) OVER(win2) AS i_event_time
  FROM (
    SELECT *, COUNTIF(event_type = 'C') OVER(win1) grp
    FROM `project.dataset.table`
    WINDOW win1 AS (PARTITION BY id, location ORDER BY event_time ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) 
  )
  WINDOW win2 AS (PARTITION BY id, location, grp ORDER BY event_time ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) 
) 
WHERE event_type = 'C' 
AND NOT i_event_time IS NULL

Эта версия обращается к некоторым крайним случаям - как, например, случай, когда есть последовательные события 'C' с "пропущенными" событиями "I", как в примере ниже

#standardSQL
WITH `project.dataset.table` AS (
  SELECT 1001 id, TIMESTAMP '2018-06-04 18:23:48.526895 UTC' event_time, 'I' event_type, 'd' location UNION ALL
  SELECT 1001, '2018-06-04 19:26:44.359296 UTC', 'I', 'h' UNION ALL
  SELECT 1001, '2018-06-05 06:07:03.658263 UTC', 'I', 'w' UNION ALL
  SELECT 1001, '2018-06-07 00:47:44.651841 UTC', 'I', 'd' UNION ALL
  SELECT 1001, '2018-06-07 00:48:17.857729 UTC', 'C', 'd' UNION ALL
  SELECT 1001, '2018-06-08 00:04:53.086240 UTC', 'C', 'd' UNION ALL
  SELECT 1001, '2018-06-12 21:23:03.071829 UTC', 'I', 'd' 
)
SELECT id, location, TIMESTAMP_DIFF(event_time, i_event_time, SECOND) AS diff
FROM (
  SELECT *, MAX(IF(event_type = 'I', event_time, NULL)) OVER(win2) AS i_event_time
  FROM (
    SELECT *, COUNTIF(event_type = 'C') OVER(win1) grp
    FROM `project.dataset.table`
    WINDOW win1 AS (PARTITION BY id, location ORDER BY event_time ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) 
  )
  WINDOW win2 AS (PARTITION BY id, location, grp ORDER BY event_time ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) 
) 
WHERE event_type = 'C' 
AND NOT i_event_time IS NULL    

результат равен

Row id      location    diff     
1   1001    d           33     

, хотя, если не учитывать указанный крайний случай, это будет

Row id      location    diff     
1   1001    d           33   
2   1001    d           83795    
0 голосов
/ 20 декабря 2018

Вы можете использовать накопительную функцию max(), чтобы получить самое последнее время i перед каждым событием.

Затем просто отфильтруйте по событию C:

select id, location,
       timestamp_diff(event_time, i_event_time, second) as diff
from (select t.*,
             max(case when event_type = 'I' then event_time end) over (partition by id, location order by event_time) as i_event_time
      from t
     ) t
where event_type = 'C';
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...