
Повний посібник з SQL для Google Analytics 4 у BigQuery: Від основ до просунутої маркетингової аналітики (частина 1)
Екосистема цифрової аналітики стрімко змінюється, і разом із нею змінюється й сам підхід до роботи з даними. Якщо раніше можна було «жити» всередині інтерфейсу Google Analytics, то сьогодні — цього вже недостатньо.
Сирі дані, які GA4 передає у BigQuery, дають повний контроль над обчисленнями. Але щоб витягти з них користь, потрібна одна ключова навичка — SQL.
Цей посібник — детальне й практичне введення в SQL на прикладі сирих даних GA4. Ми будемо рухатися крок за кроком, з поясненнями, реальними кейсами та прикладами запитів.
Частина 1: Архітектура Експорту GA4 та фундаментальні оператори
- Структура даних у BigQuery: з чого складається таблиця
- Фундаментальні Оператори SQL
Частина 2: Розрахунок кількості Користувачів та Сесій на даних експорту GA4 до BigQuery
- 2.1 Функція COUNT у поєднанні з DISTINCT: Підрахунок Користувачів
- 2.2 Оператор CONCAT: як отримати ID Сесії та порахувати кількість сесій на даних експорту GA4 до BigQuery
- 2.3 Вкладені поля (Nested Fields) та роль UNNEST у роботі з даними GA4
- 2.4 GROUP BY - виводимо розрахунки в розрізі потрібних параметрів
- 2.5 ORDER BY - як відсортувати результати
Частина 3: Побудова Звіту "Сторінки та Екрани" (Pages and Screens)
- 3.0 Структура звіту Pages and Screens: які параметри та метрики ми маємо повторити
- 3.1 Виводимо параметр page_location
- 3.2 Розрахунок Метрик
- 3.2.1 Метрика Views (Перегляди)
- 3.2.2 Метрика Total Users (Усього користувачів)
- 3.2.3 Метрика Views per user (середня кількість переглядів на користувача)
- 3.2.4 Метрика Average engagement time per user (Середній час взаємодії на користувача)
- 3.2.5 Метрика Event count (Кількість подій)
- 3.2.6 Метрика Key Events (Основні події)
- 3.2.7 Метрика Total revenue (Загальний дохід)
- 3.3 Фінальний Зведений Запит
Частина 1: Архітектура Експорту GA4 та фундаментальні оператори
Перш ніж переходити до аналізу поведінки користувачів, необхідно зрозуміти, як GA4 зберігає дані всередині BigQuery. І якщо цього не розуміти, запити будуть або дорогими, або неправильними.
Дані експорту зберігаються не у вигляді агрегованих звітів, як в інтерфейсі, а у форматі сирих подієвих записів, тобто кожен рядок у таблиці BigQuery — це окрема подія: перегляд сторінки, клік, початок сесії, взаємодія з контентом, транзакція та інші івенти, які надсилає ваш сайт або застосунок.
Саме тому перед тим, як писати будь-які SQL-запити, важливо розуміти:
- яку структуру мають таблиці експорту GA4;
- які поля в них доступні;
- які з цих полів є вкладеними структурами;
- як об’єднувати щоденні таблиці в один запит і багато іншого, про що ми поговоримо далі.
Структура даних у BigQuery: з чого складається таблиця
Після налаштування експорту GA4 у BigQuery у вас з’являється датасет, у якому для кожного дня створюється окрема таблиця формату:
events_YYYYMMDD
Щоб зрозуміти, як звертатись до цієї таблиці на SQL, важливо знати загальну ієрархію BigQuery: Project > Dataset > Таблиці

У випадку GA4 датасет завжди має назву analytics_{ga4_property_id}, а таблиці - events_YYYYMMDD. Тобто кожна таблиця — це події за один день.

Коли ви відкриваєте будь-яку з таких таблиць у BigQuery, у правій частині інтерфейсу відображається її SCHEMA — повний перелік доступних полів. На перший погляд може здатися, що це звичайна таблиця, але структура значно складніша: в деяких випадках, як наприклад, з event_params ви бачите додаткову вкладеність.

Як видно зі схеми, таблиця містить велику кількість різноманітної інформації. Ось лише приклад даних по одній події:

Серед полів, з якими ми працюватимемо найчастіше:
- event_date — дата події по часовому поясу GA4;
- event_timestamp — точний таймстемп (час) події в UNIX форматі;
- event_name — назва події;
- event_params — масив параметрів, у якому можуть міститися URL сторінки, utm-мітки,
session_id,screen_nameта інші значення; - user_pseudo_id — унікальний ідентифікатор користувача;
- traffic_source — джерело, канал та кампанія трафіку з якого користувач вперше відвідав сайт;
- device, geo— набори вкладених полів із даними про пристрій та гео.
Офіційна документація Google має повний опис схеми експорту GA4, включно з типами даних та їх вкладеністю. Рекомендую звертатися до неї щоразу, коли ви працюєте з новими параметрами або шукаєте специфічні значення.
Тепер, коли ви трохи зрозуміли схему даних - давайте напишемо перші запити.
Фундаментальні Оператори SQL
1.1 Оператор SELECT: як вибирати лише потрібні дані
Оператор SELECT - це фундаментальна частина будь-якого SQL-запиту. Його завдання — визначити, яку саме інформацію потрібно повернути з таблиці. Повний синтаксис може бути складним, але базово виглядає так:
SELECT перелік полів таблиці, які хочете вивести
FROM таблицяПро оператор FROM ми говоримо далі.
Вибір усіх полів таблиці
У найпростішому випадку оператор SELECT використовується разом зі спеціальним символом *, який означає «усі поля таблиці»:
SELECT *
FROM `project-2fdab5d4-7e4c-43c5-ab8.analytics_000001.events_20240118`
Такий запит повертає повну структуру таблиці — всі поля, (включно з вкладеними масивами та RECORD-структурами, про які ми поговоримо далі).
На практиці, звісно, такий запит не має сенсу, окрім як для пояснення основ, оскільки у вкладці Preview BigQuery можна побачити аналогічний вигляд.

У реальних задачах краще явно вказувати, які саме поля потрібні. Тому далі ми переходимо до більш точного вибору полів.
Вибір конкретних полів
Щоб отримати тільки необхідні стовпчики, ви просто перелічуєте їх назви у SELECT: наприклад, ось таким запитом, я можу отримати тільки назву події та дату, коли вона була виконана:
SELECT
event_name,
event_date
FROM `project-2fdab5d4-7e4c-43c5-ab8.analytics_000001.events_20240118`
Виконавши цей запит, або просто глянувши на скрін вище, у вас могло б з'явитися наступне запитання:
Чому в результаті є багато однакових рядків?
Відповідь проста: тому що SELECT повертає усі значення з вибраних стовпців у тому вигляді, в якому вони є в таблиці. Якщо в таблиці є 300 подій які відбулись в один і той же день - SELECT поверне 300 рядків.
Якщо потрібно отримати лише унікальні значення, слід додатково використовувати DISTINCT.
Оператор DISTINCT
DISTINCT дозволяє отримати унікальні значення поля або унікальні комбінації значень кількох полів. Давайте спробуємо отримати всі можливі комбінації параметрів джерела/каналу трафіку, з якого користувач вперше відвідав наш сайт:
SELECT DISTINCT
traffic_source.source,
traffic_source.medium
FROM `project-2fdab5d4-7e4c-43c5-ab8.analytics_000001.events_20240118`
Це дозволяє побачити:
- які саме джерела присутні в таблиці;
- які комбінації source + medium зустрічалися.
Важливо: DISTINCT застосовується до всього списку полів після SELECT.
Чому в запиті назви полів інколи пишуться через крапку?
У таблицях GA4 частина даних зберігається не окремими стовпчиками, а у вигляді вкладених структур, які містять інші поля всередині. BigQuery дозволяє звертатися до внутрішніх значень через крапку. Таким чином:
- traffic_source — це одне поле таблиці (стовпчик), всередині якого є інші параметри;
- traffic_source.source — це вже конкретне вкладене значення всередині цього поля.
- traffic_source.medium — так само, звернення до іншого внутрішнього значення.
Тобто крапкова нотація — просто спосіб “дійти” до потрібного параметра всередині складної структури.

1.2 Оператор FROM
Оператор FROM визначає, звідки саме BigQuery має взяти дані для запиту. У контексті експорту GA4 він працює максимально прямо: ми вказуємо конкретну таблицю або таблиці, з яких потрібно отримати дані. У BigQuery, як вже розбиралось вище, структура завжди однакова:
Project (Проєкт) -> Dataset (Датасет) -> Table (Таблиця)
Саме тому у FROM ми завжди бачимо шлях типу:
project-2fdab5d4-7e4c-43c5-ab8.analytics_000001.events_20240118Це означає:
- project-2fdab5d4-7e4c-43c5-ab8 — проєкт;
- analytics_000001 — датасет;
- events_20240118 — таблиця з подіями за 18 січня 2024 року.
Оскільки BigQuery — це платний сервіс із безкоштовними лімітами, перш ніж ми продовжимо розбирати основні SQL-оператори, важливо зрозуміти ціноутворення.
Вартість SQL запитів в BigQuery
Кожного разу, коли ви пишете SQL-запит, система рахує, скільки байтів інформації буде оброблено для його виконання. Саме за ці байти ви і платите. Тобто BigQuery працює за моделлю «оплата за використання».

При цьому, сервіс щомісяця надає базовий безкоштовний обсяг, якого зазвичай достатньо для малого бізнесу. Зокрема:
- 1 TiB обробки даних для SQL-запитів;
- 10 ГіБ зберігання даних у таблицях.
Оскільки ці квоти оновлюються щомісяця, для невеликих проєктів вони зазвичай повністю закривають потреби в аналізі даних. Для великих компаній витрати на BigQuery, хоча й можуть складати декілька сотень, а інколи й тисяч доларів, завжди залишаються прогнозованими, адже оплата нараховується лише за той обсяг даних, який був реально опрацьований або збережений. Офіційна інформація про вартість доступна в документації Google Cloud.
1.3 Оператор WHERE: Фільтрація та Економія Ресурсів
Оператор WHERE використовується для того, щоб відібрати з таблиці лише ті рядки, які відповідають певній умові. Найпростіше уявити його як аналог фільтра в Excel або Google Sheets: ви вказуєте поле та умову — і у відповідь отримуєте тільки потрібні рядки.
Це ключовий інструмент у роботі з BigQuery, адже таблиці GA4 містять тисячі й мільйони подій, і без фільтрації аналіз практично неможливий. Давайте розберемо деякі приклади використання цього оператора.
Порівняння значень: >, <, !=
Найпростіший запит з фільтрацією виглядає так:
SELECT
event_name,
traffic_source.source
FROM `project-2fdab5d4-7e4c-43c5-ab8.analytics_000001.events_20240118`
WHERE traffic_source.source = 'google';І в результаті отримаємо таблицю лише з тими подіями, де джерело трафіку (з якого користувач вперше відвідав сайт) дорівнює "google".

Так само можна виключити певні значення за допомогою умови “не дорівнює” (!=):
SELECT
event_name,
traffic_source.source
FROM `project-2fdab5d4-7e4c-43c5-ab8.analytics_000001.events_20240118`
WHERE traffic_source.source != 'google';При цьому WHERE може працювати не тільки з текстом, а й з числами або датами, завдяки операторам >, <, >=, <= .
Фільтрація за кількома умовами
Умови можна поєднувати через AND (виконуються всі) або OR (виконується хоча б одна):
SELECT
event_name,
traffic_source.source,
traffic_source.medium
FROM `project-2fdab5d4-7e4c-43c5-ab8.analytics_000001.events_20240118`
WHERE traffic_source.source = 'google'
AND traffic_source.medium = 'organic'
Фільтрація за частиною слова: оператор LIKE
Іноді потрібно знайти всі рядки, де поле містить певний фрагмент тексту. Для цього використовується оператор LIKE:
SELECT
event_name,
traffic_source.source
FROM `project-2fdab5d4-7e4c-43c5-ab8.analytics_000001.events_20240118`
WHERE traffic_source.source LIKE '%facebook%'Символи % означають “будь-яку кількість будь-яких символів”. Тобто в результаті ми повернемо всі варіації джерела facebook: m.facebook, lm.facebook і т.д.:

ФІльтрація за регулярними виразами (REGEX)
Ну і якщо простих умов недостатньо - завжди можна підключити регулярні вирази, використовуючи REGEXP_CONTAINS. Наприклад, в цьому випадку ми повернемо всі події де джерело трафіку відносилось до google чи facebook:
SELECT
event_name,
traffic_source.source
FROM `project-2fdab5d4-7e4c-43c5-ab8.analytics_000001.events_20240118`
WHERE REGEXP_CONTAINS(traffic_source.source, 'google|facebook')Тобто LIKE підходить для простих текстових шаблонів (“містить”, “починається з”, “закінчується на”), а REGEXP_CONTAINS підтримує повноцінні регулярні вирази для складних умов пошуку: варіантів, патернів, довжини, класів символів та пошуку по словах.

Фільтрація за датою (_TABLE_SUFFIX)
Ну і найцікавіше: у BigQuery дані GA4 зберігаються у вигляді щоденних таблиць, наприклад: events_20240101, events_20240102, events_20240103. Частина після підкреслення (20240101) — це суфікс таблиці.
Щоб звернутися одразу до кількох таблиць усередині одного датасету, чиї назви починаються однаково, у FROM використовують шаблон: events_*, наприклад:
SELECT *
FROM `project.dataset.events_*`Якщо потрібно вибрати дані лише за певний період, то ми ставимо зірочку після частини дати:
SELECT *
FROM `project.dataset.events_202401*`
А іноді потрібно взяти дані лише за певний діапазон дат. І ось тут дуже важливе: я часто зустрічаю, як ті, хто починають свій шлях в BigQuery пишуть щось типу:
SELECT
event_name,
traffic_source.source
FROM `project-2fdab5d4-7e4c-43c5-ab8.analytics_000001.events_*`
WHERE event_date BETWEEN '20240101' AND '20240131';Але хоч з точки зору синтаксису SQL це і правильно, з точки зору виставлення рахунків за BigQuery це одна з найчастіших помилок. У випадку попереднього запиту ви оплатите всі дані GA4, які у вас є в датасеті, навіть за ті дати, які вам не потрібні.
Щоб уникнути зайвих платежів, використовуйте спеціальну псевдоколонку _TABLE_SUFFIX. Виглядати запит буде так:
SELECT *
FROM `project-2fdab5d4-7e4c-43c5-ab8.analytics_000001.events_*`
WHERE _TABLE_SUFFIX BETWEEN '20240101' AND '20240131'Обидва попередні запити повертають дані лише за 1–31 січня 2024 року. Різниця тільки в тому, що в першому випадку ви оплатите всі дані, які є в датасеті. А в другому, тільки за 1–31 січня 2024 року.

Зверніть увагу, оператор BETWEEN включає в діапазон обидва кінцеві значення, тобто в нашому випадку і 1 і 31 січня.
Чому через _TABLE_SUFFIX, а не event_date?
Фільтрація через _TABLE_SUFFIX дозволяє BigQuery пропускати таблиці, які не потрапляють у діапазон, ще до їхнього сканування. Це робить запит значно швидшим і дешевшим порівняно з фільтрацією за полем event_date.
Тепер ви можете фільтрувати дані та обирати тільки потрібні колонки з таблиці, але це лише початок: найцікавіше починається з розрахунків основних показників. Саме це ми і розберемо далі.
Частина 2: Розрахунок кількості Користувачів та Сесій на даних експорту GA4 до BigQuery
Робота з даними GA4 у BigQuery починається з розуміння того, як правильно рахувати користувачів. Тому почнемо ми з них, а потім розберемо нюанси підрахунку інших показників.
Ну і щоб ми не просто розбирали якісь розрахунки в вакуумі в кінці всьго процесу, ми застосуємо отримані знання для побудови звіту Pages and Screens (Сторінки та екрани).
2.1 Функція COUNT у поєднанні з DISTINCT: Підрахунок Користувачів
У моделі даних GA4 базовим технічним ідентифікатором є user_pseudo_id — автоматично згенерований GA4 анонімний клієнтський ID, який прив’язує всі події до конкретного браузера або пристрою. Він присутній у кожному event-рядку, тому саме через нього здійснюється підрахунок унікальних користувачів.

Для підрахунку чогось в SQL використовується функція COUNT, яка підраховує кількість записів у таблиці. Наприклад, ось так я можу отримати кількість подій в таблиці:
SELECT COUNT(event_name)
FROM `project-2fdab5d4-7e4c-43c5-ab8.analytics_000001.events_20240118`Але щоб підрахувати кількість користувачів, нам потрібно перерахувати тільки унікальні user_pseudo_id, тому в додаток до COUNT використаємо DISTINCT, або іншими словами метод COUNT(DISTINCT...). Виглядати запит буде ось так:
SELECT COUNT(DISTINCT user_pseudo_id)
FROM `project-2fdab5d4-7e4c-43c5-ab8.analytics_000001.events_20240118`Як бачимо в обраний період 58 унікальних користувачів відвідало наш сайт.

Зверніть увагу, функція COUNT не рахує значення, які дорівнюють NULL. Це означає, що підраховуються лише ті рядки, де поле, яке ви вказуєте, містить реальне значення.
Якби ми не використали DISTINCT, тоді нам би повернулося число 1971:

Тобто ми б отримали лише загальну кількість рядків (переданих подій), які містять user_pseudo_id.

На основі цих підрахунків можна будувати й інші метрики. Наприклад, якщо ви хочете зрозуміти, скільки подій у середньому виконує один користувач, можна одразу обчислити все в одному запиті:
SELECT
COUNT(user_pseudo_id),
COUNT(DISTINCT user_pseudo_id),
COUNT(user_pseudo_id) / COUNT(DISTINCT user_pseudo_id)
FROM `project-2fdab5d4-7e4c-43c5-ab8.analytics_000001.events_20240118`Зверніть увагу на важливий момент: так, ми можемо робити розрахунки прямо в SELECT — наприклад, поділити кількість подій на кількість унікальних користувачів. І саме це робить SQL таким потужним.
От тільки подивіться на результат, так, наші показники розрахувались, але назви колонок…

AS для найменування колонок
Щоб колонки результатів було зручно читати, ви можете задати назву для них. Для цього використовується оператор AS. Давайте вкажемо назви для наших колонок і подивимось на результат повторно:
SELECT
COUNT(user_pseudo_id) AS events,
COUNT(DISTINCT user_pseudo_id) AS unique_users,
COUNT(user_pseudo_id) / COUNT(DISTINCT user_pseudo_id) AS avg_events_per_user
FROM `project-2fdab5d4-7e4c-43c5-ab8.analytics_000001.events_20240118`
Стало набагато краще.
Функції для математичних розрахунків
Окрім підрахунку користувачів і подій, у SQL можна виконувати інші математичні обчислення. Це дозволяє створювати додаткові метрики прямо в запитах і аналізувати поведінку користувачів у різних розрізах. Ми вже розглянули COUNT, шо рахує кількість подій у таблиці, але існують й інші:
- SUM — повертає суму всіх числових елементів у колонці. Корисно, наприклад, для підрахунку доходу за період.
SELECT
SUM(ecommerce.purchase_revenue) AS purchase_revenue
FROM `project-2fdab5d4-7e4c-43c5-ab8.analytics_000001.events_20240118`
WHERE event_name = "purchase"- AVG — обчислює середнє значення числової колонки. Функція працює лише з числовими типами даних. Це може бути корисно наприклад при розрахунку середнього чеку.
SELECT AVG(ecommerce.purchase_revenue) AS avg_check
FROM `project-2fdab5d4-7e4c-43c5-ab8.analytics_000001.events_20240118`
WHERE event_name = "purchase"- MIN/MAX — повертає найменше/найбільше значення у вибраному полі. Наприклад, ми можемо визначити першу та останню подію за день:
SELECT
MIN(event_timestamp) AS first_event_received,
MAX(event_timestamp) AS last_event_received
FROM `project-2fdab5d4-7e4c-43c5-ab8.analytics_000001.events_20240118`
Щоб перетворити значення у більш читабельний формат datetime, можна використати TIMESTAMP_MICROS():
SELECT
TIMESTAMP_MICROS(MIN(event_timestamp)) AS first_event_received,
TIMESTAMP_MICROS(MAX(event_timestamp)) AS last_event_received
FROM `project-2fdab5d4-7e4c-43c5-ab8.analytics_000001.events_20240118`
Звісно, існує набагато більше таких функцій, але ідею, думаю, ви зрозуміли. Детальніше тут.
2.2 Оператор CONCAT: як отримати ID Сесії та порахувати кількість сесій на даних експорту GA4 до BigQuery
Ще одна часта помилка, яку я зустрічаю в тих, хто тільки починає свій шлях у BigQuery - неправильний підрахунок кількості сесій. В даних експорту є значення ga_session_id і новачки часто сприймають його за унікальний id сесії. Але це помилка. ga_session_id — це timestamp, тобто час початку сесії, округлений до секунди.
Через це можливий наступний сценарій:
- два різні користувачі можуть почати сесію в одну і ту саму секунду,
- у результаті обидва отримають однаковий
ga_session_id, - тому умовний COUNT(DISTINCT ga_session_id) поверне занижену кількість сесій, оскільки сесії різних відвідувачів з однаковим timestamp початку сесії будуть пораховані, як одна сесія.
Щоб отримати коректну кількість сесій, потрібно сформувати унікальний ключ, який поєднує і ідентифікатор користувача, і час початку сесії. Але перед тим як ми це зробимо, нам потрібно розібрати ще один важливий момент.
2.3 Вкладені поля (Nested Fields) та роль UNNEST у роботі з даними GA4
Однією з головних відмінностей експорту GA4 у BigQuery від багатьох інших табличних даних є те, що дані події не зберігаються у вигляді плоскої таблиці з десятками окремих колонок. Натомість GA4 використовує вкладену структуру даних.
Найпоказовішим прикладом є поле event_params. На перший погляд це одна колонка, але всередині вона містить масив об’єктів типу RECORD, де кожен елемент — це пара:
- key — назва параметра події (наприклад,
page_location,page_title,ga_session_id) - value — об’єкт з кількома полями:
string_value,int_value,float_value,double_value.
Таким чином, замість десятків окремих колонок GA4 «пакує» параметри у вкладену структуру, що робить таблицю з однієї сторони гнучкою, а з іншої - складнішою для читання.

Щоб працювати з цими даними, ми не можемо просто написати SELECT event_params.page_location. Тому що такої колонки не існує: значення параметра знаходиться всередині масиву, і до нього потрібно звертатися за ключем. Нам потрібно "розпакувати" цей масив. Для цього використовується функція UNNEST:
SELECT
event_date,
event_name,
user_pseudo_id,
param.key,
param.value.string_value,
param.value.int_value,
param.value.float_value
FROM `project-2fdab5d4-7e4c-43c5-ab8.analytics_000001.events_20240118`,
UNNEST(event_params) AS param;У результаті кожен елемент масиву event_params стає окремим рядком для кожної з подій.

Отже, UNNEST використовується для розгортання (розпакування) масивів та вкладених структур у рядках таблиці в BigQuery.
Скалярні Підзапити — практичний спосіб працювати з параметрами GA4
Тепер коли ми зрозуміли що робить функція UNNEST, спробуємо отримати значення конкретного параметра для кожної події. Щоб отримувати значення параметра без дублювання рядків, у BigQuery використовують так звані скалярні підзапити (scalar subqueries). Це маленький запит всередині SELECT, який:
- виконує UNNEST тільки для одного конкретного рядка;
- знаходить потрібний параметр за ключем;
- повертає лише одне значення;
- додає його як нову колонку.
Наприклад, давайте витягнемо значення параметра ga_session_id у масиві event_params і повернемо його як звичайну колонку.
SELECT
event_date,
event_name,
(SELECT value.int_value
FROM UNNEST(event_params)
WHERE key = 'ga_session_id') AS ga_session_id
FROM `project-2fdab5d4-7e4c-43c5-ab8.analytics_000001.events_20240118`;У цьому запиті може виникнути питання, що значить value.int_value. У масиві event_params кожен параметр має структуру key -> value, де value — це поле типу RECORD з кількома можливими варіантами значень:
- string_value — якщо параметр є текстовим;
- int_value — якщо значення ціле число;
- double_value або float_value — якщо це число з крапкою.
Тому value.int_value означає: «візьми цілочислове значення параметра».

У результаті отримуємо додаткову колонку зі значенням ga_session_id:

Така техніка є стандартною у роботі з даними GA4 в BigQuery у випадках, коли необхідно діставати вкладені значення, перелік яких доволі великий, зокрема, але не виключно: page_location, page_title, ga_session_id, всі кастомні параметри подій.
Ну що ж, тепер коли ми можемо отримати значення ga_session_id давайте отримаємо реальний ID сесії та підрахуємо їх кількість.
Для цього використаємо новий оператор CONCAT, який об’єднує кілька значень у рядок. Давайте сформуємо цей унікальний real_session_id:
SELECT
user_pseudo_id,
(SELECT value.int_value
FROM UNNEST(event_params)
WHERE key = 'ga_session_id') AS session_start_time,
CONCAT(
user_pseudo_id,
'-',
(SELECT value.int_value
FROM UNNEST(event_params)
WHERE key = 'ga_session_id')
) AS real_session_id
FROM
`project-2fdab5d4-7e4c-43c5-ab8.analytics_000001.events_20240118`;У такому форматі кожна сесія кожного користувача отримує власний, унікальний ідентифікатор, що дозволяє точно будувати метрику sessions у BigQuery.
Важливо: якщо хоча б один аргумент функції CONCAT NULL, то й результат також буде NULL. В нашому випадку це ролі не грає. Але загалом знати це важливо, інакше в деяких складніших розрахунках ви можете отримати не те, що очікували.

Для підрахунку кількості сесій можна скористатись таким SQL запитом:
SELECT
COUNT(DISTINCT
CONCAT(
user_pseudo_id,
'-',
(SELECT value.int_value
FROM UNNEST(event_params)
WHERE key = 'ga_session_id')
)
) AS sessions
FROM `project-2fdab5d4-7e4c-43c5-ab8.analytics_000001.events_20240118`;
Альтернатива CONCAT: оператор ||
У BigQuery також можна робити конкатенацію записом:
user_pseudo_id || '-' || ga_session_id2.4 GROUP BY - виводимо розрахунки в розрізі потрібних параметрів
Після того як ми навчилися обчислювати кількість подій, кількість унікальних користувачів та кількість сесій, виникає потреба подивитися ці значення у певному розрізі. Для цього використовують оператор GROUP BY.
GROUP BY об’єднує рядки таблиці за значеннями певних полів і дозволяє застосовувати агрегатні функції (COUNT, SUM, AVG тощо) для кожної групи окремо.
Наприклад, давайте порахуємо:
- скільки подій виконали користувачі на різних типах пристроїв,
- і скільки унікальних користувачів було на кожному з них.
SELECT
device.category,
COUNT(user_pseudo_id) AS events,
COUNT(DISTINCT user_pseudo_id) AS users
FROM `project-2fdab5d4-7e4c-43c5-ab8.analytics_000001.events_20240118`
GROUP BY device.category;І ми побачимо таблицю, де кожен рядок — це окрема категорія пристрою (desktop/mobile), а поруч — кількість подій та користувачів.

Ми також можемо групувати за кількома параметрами. Наприклад, подивімося метрики в розрізі пристрою та джерел трафіку (з яких користувач вперше відвідав сайт):
SELECT
device.category,
traffic_source.source,
traffic_source.medium,
COUNT(DISTINCT user_pseudo_id) AS users
FROM `project-2fdab5d4-7e4c-43c5-ab8.analytics_000001.events_20240118`
GROUP BY
device.category,
traffic_source.source,
traffic_source.medium;І отримаємо таку таблицю:

2.5 ORDER BY - як відсортувати результати
Після того як метрики розраховані, результати зазвичай потрібно впорядкувати. Ми можемо це зробити за допомогою оператора ORDER BY, який дозволяє сортувати значення в таблиці. Наприклад, впорядкувати за спаданням/зростанням (функції DESC/ASC). Давайте впорядкуємо наш попередній запит за спаданням по кількості користувачів:
SELECT
device.category,
traffic_source.source,
traffic_source.medium,
COUNT(DISTINCT user_pseudo_id) AS users
FROM `project-2fdab5d4-7e4c-43c5-ab8.analytics_000001.events_20240118`
GROUP BY
device.category,
traffic_source.source,
traffic_source.medium
ORDER BY users DESC;
Текстові значення будуть відсортовані по алфавіту.
Частина 3: Побудова Звіту "Сторінки та Екрани" (Pages and Screens)
Тепер давайте обєднаємо всі отриманні знання і побудуємо ваш перший звіт з інтерфейсу GA4 на сирих даних. Я обрав один з найпростіших для розуміння звітів Pages and Screens (Сторінки й екрани). Саме він показує, який контент отримує найбільше уваги, як користувачі взаємодіють зі сторінками та скільки подій там відбувається.
У цій частині статті ми відтворимо цей звіт повністю у SQL, крок за кроком — так, щоб він працював без семплінгу, без обмежень інтерфейсу та з повним контролем над логікою обчислень.
3.0 Структура звіту Pages and Screens: які параметри та метрики ми маємо повторити
Перш ніж переходити до SQL, треба чітко розуміти, які саме дані присутні у звіті GA4. Google офіційно описує структуру звіту у своїй довідці.
Параметри у звіті Pages and Screens (Сторінки й екрани):
- Content group (Група контенту) — група контенту.
- Hostname — домен.
- Page path and screen class (Шлях до сторінки й клас екрана) — шлях сторінки (разом із query string) або клас екрана.
- Page title and screen class (Назва сторінки й клас екрана) — заголовок сторінки чи клас екрана.
- Page title and screen name (Назва сторінки й екрана) — заголовок сторінки чи ім’я екрана.
Для статті ми сфокусуємося на найпопулярнішому параметрі — Page Path (Шлях до сторінки), бо саме з нього зазвичай починають аналіз і саме він є основою звіту в інтерфейсі.

Метрики у звіті:
- Views (Перегляди) — перегляди сторінки.
- Active users (Активні користувачі) — це користувачі, які по мірках команди GA4 були активні в період аналізу. Я вважаю, що активність на кожному проекті має рахуватись по своєму, тому ми будемо рахувати Total Users, а не Active Users, але все по порядку.
- Views per active user (Кількість переглядів на активного користувача) — середня кількість переглядів на активного користувача, в нашому випадку просто на користувача.
- Average engagement time per active user (Середній час взаємодії на активного користувача) — середній час взаємодії зі сторінкою на одного користувача.
- Event count (Кількість подій) — кількість подій.
- Key Events (Основні події) — кількість ключових подій (конверсій).
- Total revenue (Загальний дохід) — дохід, сформований на сторінці.

Усі ці метрики ми відтворимо в BigQuery.
3.1 Виводимо параметр page_location
У звіті Pages and Screens (Сторінки й екрани) перший стовпчик — це параметр Page path and screen class (Шлях до сторінки й клас екрана). Саме він задає розріз, у якому показуються всі інші метрики (Views, Users, Event count тощо).
У сирих даних GA4 в BigQuery шлях до сторінки зберігається в параметрі page_location всередині масиву event_params. Це поле містить повний URL сторінки (разом із доменом та параметрами запиту). На першому кроці нас влаштовує саме page_location — ми просто навчимося його діставати.
Давайте отримаємо page_location за допомогою UNNEST. Починаємо з простого запиту, який:
- бере таблицю подій GA4
- розпаковує масив event_params функцією UNNEST,
- витягує з нього тільки значення з ключем page_location,
- додає його в окрему колонку page_location.
SELECT
-- Витягуємо URL сторінки з event_params
(SELECT value.string_value
FROM UNNEST(event_params)
WHERE key = 'page_location') AS page_location,
-- Виводимо всі інші стандартні колонки події
*
FROM `project_name.dataset_name.events_YYYYMMDD`;Оскільки це скалярний підзапит у SELECT, ми отримуємо одне значення page_location на кожен рядок events-таблиці. Далі * додає всі інші стандартні колонки (event_name, event_timestamp, user_pseudo_id тощо), щоб було зручно звірятися з даними.
Як результат — у нас з’являється перший стовпчик майбутнього звіту Pages and Screens (Сторінки й екрани): URL сторінки, за яким ми згодом будемо групувати всі метрики.
3.2 Розрахунок Метрик
Маючи базовий параметр page_location, ми можемо переходити до побудови метрик зі стандартного звіту Pages and Screens (Сторінки й екрани).
3.2.1 Метрика Views (Перегляди)
Перегляд — це подія page_view. Щоб порахувати кількість переглядів, найзручніше використати функцію COUNTIF, яка рахує тільки ті рядки, що відповідають певній умові.
COUNTIF(event_name = 'page_view') AS viewsВрахуйте, що у вебі це подія page_view, але якщо вам потрібно для мобільних додатків використовуйте — screen_view.
3.2.2 Метрика Total Users (Усього користувачів)
Тут ви вже знаєте, ми використовуємо COUNT(DISTINCT...) по колонці user_pseudo_id — унікальному ідентифікатору браузера/пристрою в GA4. Оскільки ми групуємо по сторінці, це покаже кількість унікальних користувачів, які відвідали конкретну сторінку.
COUNT(DISTINCT user_pseudo_id) AS usersЦе кількість всіх користувачів, які взаємодіяли зі сторінкою.
У стандартних звітах GA4 показник “Users” означає Active users (Активні користувачі), але в BigQuery ми отримуємо Total users (Усього користувачів), тобто всіх користувачів без фільтра активності. Це нормальна й очікувана відмінність.
3.2.3 Метрика Views per user (середня кількість переглядів на користувача)
Після того як ми отримали базові метрики — кількість переглядів (views) та кількість користувачів (users), — можна переходити до розрахунку похідних показників. Одним з ключових є Views per user (середня кількість переглядів на користувача), тобто середня кількість переглядів, яку здійснив один користувач на конкретній сторінці.
У GA4 цей показник відображає, наскільки “повертаються” користувачі на сторінку та як часто вони з нею взаємодіють. У BigQuery його легко відтворити у вигляді простого ділення однієї метрики на іншу.
Формула складається з двох частин, які ми вже розрахували:
- чисельник: кількість подій
page_view - знаменник: кількість унікальних користувачів
user_pseudo_id
Підсумкова формула виглядає так:
COUNTIF(event_name = "page_view") / COUNT(DISTINCT user_pseudo_id) AS views_per_userТобто ми просто ділимо кількість переглядів на кількість людей, які здійснили ці перегляди.
3.2.4 Метрика Average engagement time per user (Середній час взаємодії на користувача)
Середній час взаємодії — один із ключових поведінкових показників GA4. Він відображає не просто час перебування на сторінці, а період, коли користувач реально взаємодіє зі сторінкою або бачить її у фокусі браузера.
У BigQuery ця метрика не існує як готове поле, її потрібно відтворити вручну, використовуючи параметр engagement_time_msec. Це значення передається у кожному івенті, який відправляється у період активної взаємодії користувача з сайтом.
Як GA4 формує engagement_time_msec
У GA4 взаємодія — це неперервний процес. Поки сторінка активна, браузер регулярно відправляє події (scroll, user_engagement тощо) з накопиченим часом.
Наприклад, це може бути такий хід подій:
| Подія | engagement_time_msec | Що означає |
|---|---|---|
scroll | 8781 | Користувач прокрутив сторінку ~8.7 сек |
user_engagement | 11856 | Користувач перейшов на наступну сторінку. Система передала ще 11.8 сек взаємодії |
Ці значення — частини одного й того самого накопичувального часу. Щоб його отримати, треба додавати всі ці шматочки.
Отже, давайте збирати Average engagement time per user (Середній час взаємодії на користувача) у SQL:
- Витягуємо значення
engagement_time_msecіз event_params
Це окремий параметр у масиві event_params. Для кожного рядка таблиці виконується скалярний підзапит:
(SELECT value.int_value
FROM UNNEST(event_params)
WHERE key = "engagement_time_msec")Цей підзапит повертає:
- або число (мс),
- або NULL (якщо подія не має інформації про час взаємодії).
2. Сумуємо всі значення для конкретної сторінки
Кожен рядок містить частину взаємодії, тому всі значення потрібно додати:
SUM(
(SELECT value.int_value
FROM UNNEST(event_params)
WHERE key = "engagement_time_msec")
)Це дає загальний engagement time для всіх подій на сторінці.
3. Ділимо на кількість користувачів.
SUM(...) / COUNT(DISTINCT user_pseudo_id)4. Переводимо мілісекунди у хвилини
- 1000 — мілісекунди в секунду
- 60 — секунди в хвилину
/ 1000 / 605. З’єднуємо все в фінальну формулу метрики:
SUM(
(SELECT value.int_value
FROM UNNEST(event_params)
WHERE key="engagement_time_msec")
) / COUNT(DISTINCT user_pseudo_id) / 1000 / 60 AS avg_engagement_time3.2.5 Метрика Event count (Кількість подій)
Ця метрика показує, скільки подій відбулося на сторінці. Наприклад, у моїх тестових даних є подія з назвою click_button яка позначає клік на кнопку.
COUNTIF(event_name = "click_button") AS event_countВажливо зберігати саме таке написання події, як у даних GA4.
Таким же способом можна додавати у звіт інші івенти — наприклад: scroll, file_download, sign_up тощо.
3.2.6 Метрика Key Events (Основні події)
У GA4 ключові події — це ті, що позначені як Key events (Основні події). У SQL ми можемо рахувати будь-які події. Наприклад, давайте використаємо подію purchase (покупка).
COUNTIF(event_name = "purchase") AS conversions3.2.7 Метрика Total revenue (Загальний дохід)
У BigQuery дохід від покупки доступний через поле ecommerce.purchase_revenue.
SUM(ecommerce.purchase_revenue) AS total_revenueЗверніть увагу:
- якщо сайт не використовує eCommerce, значення буде 0;
- якщо на сторінці немає транзакцій, значення буде 0.
3.3 Фінальний Зведений Запит
На цьому кроці ми вже маємо все необхідне:
- параметр, за яким будуємо розріз — page_location;
- набір метрик: views, users, views_per_user, avg_engagement_time, event_count, conversions, total_revenue.
Залишається об’єднати їх в один запит, згрупувати за сторінкою і відсортувати.
SELECT
-- Параметр: шлях сторінки (Page path)
(SELECT value.string_value
FROM UNNEST(event_params)
WHERE key = "page_location") AS page_location,
-- Метрика: перегляди
COUNTIF(event_name = "page_view") AS views,
-- Метрика: користувачі
COUNT(DISTINCT user_pseudo_id) AS users,
-- Метрика: перегляди на користувача
COUNTIF(event_name = "page_view") / COUNT(DISTINCT user_pseudo_id) AS views_per_user,
-- Метрика: середній час взаємодії (хвилини)
SUM(
(SELECT value.int_value
FROM UNNEST(event_params)
WHERE key = "engagement_time_msec")
) / COUNT(DISTINCT user_pseudo_id) / 1000 / 60 AS avg_engagement_time,
-- Метрика: кількість подій
COUNTIF(event_name = "click_button") AS event_count,
-- Метрика: конверсії (key events)
COUNTIF(event_name = "purchase") AS conversions,
-- Метрика: дохід
SUM(ecommerce.purchase_revenue) AS total_revenue
FROM `project_name.dataset_name.events_YYYYMMDD`
GROUP BY
page_location
ORDER BY
views DESC;
Вітаю, тільки що ви побудували свій перший звіт на сирих даних GA4.
Висновки
Робота з експортом GA4 у BigQuery відкриває перед аналітиками зовсім інший рівень можливостей. Те, що в інтерфейсі подається у вигляді готових метрик і агрегованих звітів, у BigQuery перетворюється на сирі дані — і саме SQL стає інструментом, який дозволяє зібрати ці події у змістову аналітичну картину.
Основні моменти, на яких будується робота з даними GA4 у BigQuery, можна сформулювати так:
- Структура таблиць визначає логіку аналізу.
GA4 експортує події у вигляді вкладених структур та масивів. Без розуміння моделі даних складно коректно витягнути навіть базовий параметр. Вміння працювати з event_params через UNNEST та скалярні підзапити — це фундамент. - Ідентифікація користувачів і сесій — це не “очевидні” операції.
user_pseudo_id дозволяє швидко рахувати унікальних користувачів по логіці device-based, а ga_session_id потребує додаткової обробки, щоб уникнути повторів між різними користувачами. - SQL дозволяє відтворювати звіти GA4 без обмежень.
Ми побудували всі ключові метрики Pages and Screens (Сторінки й екрани) вручну — від Views (Перегляди) і Total users (Усього користувачів) до Average engagement time per user (Середній час взаємодії на користувача) та Total revenue (Загальний дохід). Кожна формула прозора: аналітик бачить, з яких подій і параметрів вона складається, і може адаптувати логіку під конкретні бізнес-завдання. - BigQuery — це не лише “повторення” GA4, а можливість піти далі.
SQL немає семплінгу, немає прихованих обчислень, немає обмежень інтерфейсу. Ви контролюєте кожну частину метрики та можете будувати аналітику точно так, як цього потребує ваш бізнес. - BigQuery - це набагато більше ніж просто робота з сирими даними.
Так, про цей останній пункт в статті не було сказано багато, тому рекомендую вам прочитати на цю тему іншу статтю - Все, що треба знати про BigQuery: що це, навіщо та які переваги для маркетингу.

Завантаження коментарів…