У меня есть набор результатов BigQuery, содержащий события веб-сайта, которые можно сгруппировать и отсортировать по нескольким столбцам, включая отметку времени, тип события и идентификатор пользователя.
Для каждого userId я хотел бы вернуть первую строку с отметкой времени event_type_1
(вход в систему), а затем для того же пользователя вернуть первую строку event_type_2
(pageView), но только если event_type_2.timestamp
> = event_type_1.timestamp
. Повторите эти действия для полдюжины типов событий и верните результаты для всех пользователей.
Я знаю, что могу сделать это, используя именованные подзапросы, например, предложение WITH, как показано в следующем примере. Но это неэффективно, поскольку он запускает подзапрос для каждой ссылки на него. Подзапрос внутри оператора WITH выполняется примерно за 5 секунд, тогда как весь запрос занимает кратное 5 секунд, в зависимости от того, сколько раз ссылается на подзапрос.
WITH filtered_events AS
(
SELECT * FROM per_user_events ORDER BY userId, timestamp -- note: this is vastly simplified
),
event_type_1 as (
SELECT *
FROM filtered_events
WHERE filtered_events.type = 1),
event_type_2 as (
SELECT filtered_events.*
FROM filtered_events
INNER JOIN event_type_1 ON event_type_1.userId = filtered_events.userId
WHERE filtered_events.type = 2
AND filtered_events.timestamp >= event_type_1.timestamp),
event_type_3 as (
SELECT filtered_events.*
FROM filtered_events
INNER JOIN event_type_2 ON event_type_2.userId = filtered_events.userId
WHERE filtered_events.type = 3
AND filtered_events.timestamp >= event_type_2.timestamp),
event_type_4 as (
SELECT filtered_events.*
FROM filtered_events
INNER JOIN event_type_3 ON event_type_3.userId = filtered_events.userId
WHERE filtered_events.type = 4
AND filtered_events.timestamp >= event_type_3.timestamp)
SELECT * FROM event_type_1
UNION DISTINCT
SELECT * FROM event_type_2
UNION DISTINCT
SELECT * FROM event_type_3
UNION DISTINCT
SELECT * FROM event_type_4
ORDER BY userId, timestamp
Я знаю, что могу материализовать подзапрос как временную или постоянную таблицу BQ, если моя единственная цель - более быстрые запросы / меньше ресурсов. Но мне интересно, могут ли оконные функции (для каждого пользователя) найти первую event_type_1
по метке времени, а затем найти первую event_type_2
, которая приходит после timestamp1, затем первую event_type_3
после метки времени2 и т. д.
Я знаком с использованием оконной функции ROW_NUMBER() OVER (PARTITION BY)
для выбора подмножества строк для каждого события, но это не помогает мне пропустить прошлые экземпляры события2, которые приходят до события1, и, следовательно, заканчиваются с желаемой последовательностью событий event1 -> event2 -> event3 для каждого пользователя.