BigQueryにエクスポートされたGA4のデータを取り扱う際にぶつかる大きな壁が「UNNEST(アンネスト)処理」となる。つまり、テーブル構造が1行1行の単純構成になっておらず、1行の中に入れ子になっているテーブル構成のため、入れ子になっているデータを単純にSELECT文で取り出そうとしてもエラーとなるため、UNNNEST処理が必要になる。

ネスト(入れ子)構造とは
例としてpage_viewイベントを例にどのようにUNNEST処理が必要になるのかを解説する。GA4のRawデータでは、1つのpage_viewイベントに対して、以下のようなデータ構成になっている。
- event_name:page_view
- event_params.key:
∟ page_location(URL): https://example.com/home
∟ page_title(タイトル): ホーム画面
∟ ga_session_id(セッションID): 123456789
これをBigQueryのGA4のテーブルをみると、1行のなかに複数のパラメータが縦に並んで入っているように見え、これがネストされた状態といえる。このネストされた、例えばpage_locationの値を取り出そうとしても、そのままでは取り出せず、UNNESTでフラットな表形式に直す必要がある。
UNNESTでフラット化して抽出

UNNESTでテーブルをフラット化するとは、つまり入れ子状態のデータ構成を、ネストされていない1行1行の構成に直すということをUNNESTという。例えば、event_params.keyのpage_titleやpage_locationを取り出したければ、そのままSELECT文で取得することはできないため、UNNEST処理を施す必要がある。
UNNEST処理のサンプルクエリ
page_titleとpage_locationの値を取得するクエリは以下の通り。
CREATE TEMP FUNCTION date_from() RETURNS STRING AS ('20260601');
CREATE TEMP FUNCTION date_to() RETURNS STRING AS ('20260601');
WITH
tmp_01 AS (
SELECT
event_name,
REGEXP_REPLACE((SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'page_location'), r'\?.*$', '') AS page_location,
(SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'page_title') AS page_title
FROM
`<project>.<dataset>.events_*`
WHERE 1 = 1
AND _TABLE_SUFFIX BETWEEN date_from() AND date_to()
AND event_name = 'page_view'
)
SELECT
*
FROM
tmp_01▼クエリ解説
REGEXP_REPLACE((SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'page_location'), r'\?.*$', '') AS page_location- 局所的なUNNESTの発生
BigQueryは、手順1で決まった1つの page_view 行に紐づく event_params(配列の箱)の中身だけを、メモリ上の超ミニテーブルに一時的に縦展開(UNNEST)される。 - フィルタリングと抽出
展開されたミニテーブルに対して、すぐ後ろの WHERE key = ‘page_location’ を実行し、合致する1行だけに絞り込む。 - 値を1つだけ返す(スカラ副問い合わせ)
絞り込まれた行から value.string_value(例: https://sem-report.com/?p=123)を抽出する。 - 関数の適用
外側にある REGEXP_REPLACE 関数が走り、URL末尾のクエリパラメータ(?p=123)をカットして、https://sem-report.com/ に整形する。
この値が、新設された page_location という列の「値」 として、page_view の右側に配置される。
UNNESTの構文

- 全体を囲む ( ) =「1つの値に変換」
SELECT句のなかに、さらに SELECT を書く(副問い合わせをする)場合、必ず全体を ( ) で囲む必要がある。この括弧には、「中のクエリを実行して、最終的に『1つの値(文字列や数値など)』として外側に返す」という意味を持つ。 - FROM UNNEST(event_params) =「探索範囲は、この行の箱の中だけ」
通常のクエリであれば FROM テーブル名 と書くが、ここでは FROM UNNEST(event_params) と記述。これは、「今処理している、まさにその1行に紐づいている event_params(配列の箱)の中身だけを、ミニテーブルとして展開して使う」という意味になる。他の行のデータは一切見に行かない。 - WHERE key = ‘page_location’ =「名札で狙い撃ち」
UNNESTされて目の前に並んだパラメータの中から、key が page_location である行(名札がついているデータ)だけに絞り込む。 - SELECT value.string_value =「中身の抽出」
絞り込まれたデータから、文字列が入っている value.string_value の中身(URLなど)を抽出。
この構文を使う上では、「戻ってくる結果は、絶対に1行・1列(=1つの値)でなければならない」というルールがあり、これをデータベース用語でスカラ値と呼ぶ。もし、この副問い合わせの結果が「2行以上」になってしまうと、エラーを出して処理がストップする。
であるが、GA4の仕様上、1つのイベント(1行)の中に、page_location や page_title という同じ名前の key は絶対に1つしか存在しないルールになっているため、WHERE key = ‘page_location’ で絞り込めば、結果は必ず1行(1つの値)になる。だからこそ、この構文がエラーになることはない。
『Googleアナリティクス4 完全入門』 書籍販売中!