GA4's reports answer the common questions. The raw data answers the rest: any breakdown, any date range, and joins to orders, CRM or ad spend. Most GA4 SQL examples online are written for BigQuery. This series is written for Databricks.
Getting the data in.
GA4 exports its raw events to BigQuery only, so they reach Databricks from there. The best route for everyday reporting is a daily copy into a Delta table, which keeps the nested structure. Getting GA4 data into Databricks explains the options.
The examples assume the data is in one Delta table called ga4.events. Replace it with the full name of your own table.
How the GA4 data is shaped.
There's one row for every event. The columns that matter most for basic reports:
event_date: the date as text, such as20261104event_timestamp: the time in microseconds, in UTCevent_name: such aspage_vieworpurchaseevent_params: a list of keys and values, such aspage_locationandga_session_iduser_pseudo_id: the anonymous ID for a browser or app installdevice,geo,ecommerceanditems: nested groups of fields
Each event parameter has a key and a value. The value sits in one of three fields, string_value, int_value or double_value, depending on its type. Most of the work in GA4 SQL is pulling the right parameter out of that list.
An example: page views by page.
This counts page views for each page in November 2026. filter() keeps the parameter whose key is page_location, and try_element_at() takes the first one:
SELECT
try_element_at(
filter(event_params, p -> p.key = 'page_location'), 1
).value.string_value AS page_location,
COUNT(*) AS page_views
FROM ga4.events
WHERE event_date BETWEEN '20261101' AND '20261130'
AND event_name = 'page_view'
GROUP BY page_location
ORDER BY page_views DESC
When an event doesn't have the parameter, try_element_at() returns nothing rather than an error. Fields in nested groups need no special handling: device.category or geo.country work like any other column.
Dates and times.
event_date is text, which is fine for filtering because '20261101' sorts before '20261130'. To turn it into a real date, or the timestamp into a time:
SELECT
to_date(event_date, 'yyyyMMdd') AS day,
timestamp_micros(event_timestamp) AS event_time,
event_name
FROM ga4.events
WHERE event_date = '20261103'
The timestamp is in UTC. GA4's own reports use the property's time zone, so event_date follows that time zone, and the two can fall on different days near midnight.
Keeping queries fast.
Always filter on event_date, and select only the columns you need. Partitioning or clustering the Delta table on event_date means a query for one month reads only that month. For dashboards, summarise the raw events into smaller tables once a day, rather than querying every event each time.
The series.
Articles in the series are listed here as they're published, from December 2026 to January 2027:
Marc Alexander sets up the export, the GA4 model and the reporting tables as part of GA4 and Databricks.
Sources.
- Google Analytics Help: BigQuery Export schema
- Databricks: filter function
- Databricks: try_element_at function
- Databricks: to_date function
- Databricks: timestamp_micros function
Checked on 4 November 2026.