【BigQuery】STRUCT型って一体なに?ARRAY型との合わせ技で柔軟なデータ構造を操作する

 

こんにちは。CARTA ZEROのアナリティクス担当の鉄羅陀です。

 

前回の記事【BigQuery】ARRAY,UNNESTって一体なに?では

 

  • 1)ARRAY型の紹介

  • 2)UNNEST演算子の使いどころ

の2点を説明し、実際にARRAY型のカラムをUNNEST演算子で行に展開&フラット化する例を紹介しました。


今回の記事ではARRAY型と組み合わせて使用されることの多いデータ型、STRUCT型についてご紹介したいと思います。

 

今回の記事のポイントは以下2点です。

 

  • 1)STRUCTの紹介

  • 2)ARRAY型×STRUCT型を組み合わせたデータ構造の紹介~操作方法


 

STRUCT型

🤔そもそもSTRUCT型とは?

 

BigQuery公式ドキュメント:Struct_typeのSTRUCT型の定義を確認してみましょう

定義:順序付けられたフィールドのコンテナで、各フィールドは型(必須)とフィールド名(オプション)を持つデータ構造

 

 

.....。定義だけ読んでもよくわからないので、もっとかみ砕いて表現するとSTRUCT型とは,異なるデータ型を持ったいろんなデータをまとめて保有することができるデータ構造です。

 

 

具体例として、アーティスト「YOASOBI」のメンバーである「Ayase」さんをSTRUCT型で表現してみました。

(題材はなんでもいいでのですが、本稿執筆中ちょうどYOASOBIの曲が流れてきたので💁)

 

STRUCT構造の例1

--アーティスト「YOASOBI」のメンバー「Ayase」さんをSTRUCT型で表現
SELECT
  STRUCT(
     '非公表' AS full_name 
     ,'Composer' AS role
     ,31 AS age
   ) AS ayase
;


結果は以下です。

query_result_with_struct_type_1確かに「ayase」というSTRUCT型のカラムは、異なるデータ型(STRING型、INT64型)を持ったいろんなデータ(full_name, role, age)をまとめて保有できていることが確認できます。

 

 

ついでにこの例を通じて、STRUCT型の厳密な定義も読み解いてみましょう。

定義:順序付けられたフィールドのコンテナで、各フィールドは型(必須)とフィールド名(オプション)を持つデータ構造

    • コンテナ

      • 「ayase」カラムそのものを指しています。

         

    • 各フィールドは型(必須)とフィールド名(オプション)を持つ

      • 各フィールドは以下のような型・フィールド名を持っています

        • フィールド名:full_name (STRING型)

        • フィールド名:role (STRING型)

        • フィールド名:age (INT64型)

 

「ayase」という人物を大きなコンテナと見立てて、その中に「ayase」を構成(=STRUCT)している小さなデータを次々入れていく。STRUCT型はそのようなデータ構造を持つイメージを持つとわかりやすいと思います。

 

 

 

 

✍️STRUCT型の操作(各フィールドへのアクセス方法)

 

STRUCT型内の個別のフィールド値を取り出すには、ドット演算子 (.) を使用します。

以下の記法で、STRUCT型内に存在するそれぞれのフィールドへアクセスできます。

STRUCT型のカラム名.フィールド名

 

例えば「ayase」からageを取得したければ、

--アーティスト「YOASOBI」のメンバー「Ayase」さんをSTRUCT型で表現
WITH struct_sample AS (
SELECT 
  STRUCT(
     '非公表' AS full_name 
     ,'Composer' AS role
     ,31 AS age
   ) AS ayase
)

--ayase内に存在するageフィールドへアクセスする
SELECT ayase.age FROM struct_sample
;

を実行します。結果は以下になります。

query_result_with_struct_type_2

 

 

 

 

 

ARRAY型×STRUCT型を組み合わせたデータ構造

💡ARRAY型とSTRUCT型を組み合わせて柔軟なデータ構造を定義する

 

この合わせ技がなかなか強力で、理解するとSQL内でかなり柔軟なデータ構造を定義することが可能になります。

(※実際GA4データをBigQueryにエクスポートしたときに作成されるイベントテーブルでは、「events_params」フィールドなどでこの合わせ技が使用されています)

 

今度はアーティスト「YOASOBI」自体をSTRUCT型、そしてARRAY型も組み合わせてもっと柔軟に表現してみましょう。

 

STRUCT構造の例2

--アーティスト「YOASOBI」をSTRUCT型で表現したクエリ
SELECT
  STRUCT(
    --活動開始日(DATE型)
    DATE('2019-10-01') AS debut_date,

    --活動継続中か(BOOL型)
    TRUE AS is_active,
    
    -- メンバー情報(ARRAY<STRUCT>型)
    [

      --Ayaseの情報(STRUCT型)
      STRUCT(
        'Ayase' AS name
        ,'非公表' AS full_name
        ,'Composer' AS role
        ,31 AS age
      ),

      --ikuraの情報(STRUCT型)
      STRUCT(
        'ikura' AS name
        ,'幾田りら' AS full_name
        ,'Vocalist' AS role
        ,25 AS age
      )

    ] AS members,
    
    -- 代表曲リスト(ARRAY<STRING>型)
    ['アイドル', '夜に駆ける', '群青'] AS hit_songs
  
  ) AS yoasobi
;

 

実際に上記クエリを実行した結果です。

query_result_with_struct_type_3

 

うーん、一見するとわかりにくいですね。「yoasobi」というSTRUCT型のカラムがどうなっているのかを少しだけ丁寧に解説します。

  • 「yoasobi」カラム(STRUCT型)は以下のフィールドを内部に持っています。

    • フィールド名:debut_date (DATE型)

    • フィールド名:is_active (BOOL型)

    • フィールド名:members (ARRAY型)

      • 1番目の要素はAyaseの情報がはいったSTRUCT型のカラムです。以下のフィールドを内部に持っています

        • フィールド名:name  (STRING型)

        • フィールド名:full_name (STRING型)

        • フィールド名:role (STRING型)

        • フィールド名:age (INT64型)

      • 2番目の要素はikuraの情報がはいったSTRUCT型のカラムです。以下のフィールドを内部に持っています

        • フィールド名:name  (STRING型)

        • フィールド名:full_name (STRING型)

        • フィールド名:role (STRING型)

        • フィールド名:age (INT64型)

    • フィールド名:hit_songs (ARRAY型)


ポイントは

フィールド名:members (ARRAY型)

です!

 

 members自体はARRAY型のカラムですが、の中の要素がSTRUCT型になっています。


 

なんとなく「yoasobi」というSTRUCT型のカラムがどうなっているのかイメージできたのではないでしょうか...?

 

 

 

 

 

✍️定義した柔軟なデータ構造を扱う練習


練習として、「yoasobi」カラムからikuraさんの本名を取得してみましょう。

 

🤔Q.yoasobiカラムから name = 'ikura'となっている人物のfull_nameの値を取得するには?

 

 

早速結論ですが、以下のクエリで求めることが出来ます。

 

回答例

--アーティスト「YOASOBI」をSTRUCT型で表現したクエリ
WITH struct_sample AS (
  SELECT
    STRUCT(
      --活動開始日(DATE型)
      DATE('2019-10-01') AS debut_date,

      --活動継続中か(BOOL型)
      TRUE AS is_active,
    
      --メンバー情報(ARRAY<STRUCT>型)
      [

        --Ayaseの情報(STRUCT型)
        STRUCT(
          'Ayase' AS name
          ,'非公表' AS full_name
          ,'Composer' AS role
          ,31 AS age
        ),

        --ikuraの情報(STRUCT型)
        STRUCT(
          'ikura' AS name
          ,'幾田りら' AS full_name
          ,'Vocalist' AS role
          ,25 AS age
        )

      ] AS members,
      
      --代表曲リスト(ARRAY<STRING>型)
      ['アイドル', '夜に駆ける', '群青'] AS hit_songs
  
  ) AS yoasobi
)

SELECT
  member.full_name  
FROM struct_sample
CROSS JOIN UNNEST(yoasobi.members) AS member
WHERE member.name = 'ikura' 
;

 

わかりにくい部分はこの部分ですね。

FROM struct_sample
CROSS JOIN UNNEST(yoasobi.members) AS member
;

この部分を、UNNEST演算子のルール(詳しくはこちら)に対応させながら何が起こっているのかを確認していきます。

 

 

✅UNNEST演算子は引数として「FROM句で指定したソーステーブル」のARRAY型のカラムを取る

 

👉UNNEST演算子は引数としてソーステーブル「struct_sample」のARRAY型のカラム「yoasobi.members」を取っている。

 

👉「yoasobi」カラムはSTRUCT型なので、ドット演算子 (.) を使用して「members」フィールドにアクセスしている。

 

 


受け取ったARRAY内にある各値を、一組の行に変換(フラット化)する

 

👉受け取ったARRAY型のカラム「yoasobi.members」にある各値を一組の行に変換(フラット化)している

  • 1行目は「Ayaseに関するSTRUCT」

  • 2行目は「ikuraに関するSTRUCT」



ここまでの操作で出来上がるテーブルイメージは以下のようになります。

query_result_with_struct_type_4

 

あとは簡単ですね。

 

👉WHERE句:「member」カラムはSTRUCT型なので、ドット演算子 (.) を使用して「name」フィールドにアクセスし、member.name = 'ikura'の行だけフィルタリング

 

 

👉SELECT句:「member」カラムはSTRUCT型なので、ドット演算子 (.) を使用して「full_name」フィールドにアクセスし抽出

 

最終的に以下の結果になります。

query_result_with_struct_type_5

 

 

 

 

💡GA4データをBigQueryにエクスポートしたときに作成されるイベントテーブルも同じデータ構造を持っている

 

最後に、GA4データをBigQueryにエクスポートしたときに作成されるGA4イベントテーブルの「events_params」カラムも、同じようなデータ構造を持っていることを紹介して終わりたいと思います。

 

早速ですが以下のクエリを実行してみましょう。

 

疑似的にGA4イベントテーブルの構造を再現するクエリ

SELECT
  'page_view' AS event_name,
  1760686553983228 AS event_timestamp,

  --event_paramsフィールド(ARRAY<STRUCT>)
  [
    STRUCT(
      'page_title' AS key,
      STRUCT(
        '【BigQuery】STRUCT型って一体なに?' AS string_value,
        NULL AS int_value,
        NULL AS float_value,
        NULL AS double_value
      ) AS value
    ),

    STRUCT(
      'ga_session_id' AS key,
      STRUCT(
        NULL AS string_value,
        1760686553 AS int_value,
        NULL AS float_value,
        NULL AS double_value
      ) AS value
    ),
 
    STRUCT(
      'source' AS key,
      STRUCT(
        'google' AS string_value,
        NULL AS int_value,
        NULL AS float_value,
        NULL AS double_value
      ) AS value
    )

  ] AS event_params
;

 

実行結果は以下になります。

query_result_with_struct_type_6

GA4イベントテーブルの「events_params」カラムとまったく同じ構造になっています!

「events_params」もARRAY型とSTRUCT型を組み合わせて表現されているんですね。

 

 

👉補足「event_params」カラムはARRAY型

 

GA4イベントテーブルを成型するクエリ内では頻繁に以下のような操作を記述することがあると思います。

 

GA4イベントテーブルを成型するクエリ例

--GA4イベントテーブルをフラット化するよくあるクエリ
SELECT
  event_name

  ,event_timestamp

,(SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'page_title') AS page_title

........省略


--GA4イベントテーブル
FROM PROJECT.analytics_123456789.events_20251016

実は「event_params」がARRAY型なので、UNNEST演算子の引数にすることが可能なんです。

 

 



いかがだったでしょうか。今回は

  • 1)STRUCTの紹介

  • 2)ARRAY型×STRUCT型を組み合わせたデータ構造の紹介~操作方法

をご紹介しました。

 

特にARRAY型×STRUCT型を組み合わせると、SQL内でかなり柔軟なデータ構造を定義することが可能になることがお判りいただけたかと思います。

 

GA4イベントテーブルをフラット化する際、何気なく実行していたクエリの理屈もご理解いただけたのではないでしょうか?

 

昨今、生成AIでほとんどのクエリを0から作成できるようになったわけですが、指示用プロンプトの質を高める要素の1つとして、今回ご紹介したような「データ構造への深い理解」は重要な要素である。と個人的には考えています。

 

 

🎯 データをうまく「活用」できてないと感じたなら

  • 社内にデータはたまっているけど活用方法のイメージが湧かない

  • そもそも自社にとってどんなデータを収集・蓄積すればいいのかわからない

  • 広告を現在打っているが、利益に直結しているのかが不透明


📣 その課題、私たち Data Dig(データディグ)にお任せください

 

私も含めData Dig(データディグ)に所属するデータアナリスト・データプランナーは「Data Dig(データディグ)」というCookieに依存しないデジタルマーケティング展開の支援も行っています。

これからのデジタルマーケティングは、自社の1st Partyデータ(顧客データ、購買履歴データ、CRM/SFAデータ)をいかに堅牢な構造で収集・活用するかが、ビジネス成長の鍵となります。

 

 

Data Digがご支援できるデータ領域例

  • GA4アクセスログ、1st Partyデータ(顧客データ、購買履歴データ、CRM/SFAデータ)などを利用した機械学習モデル構築相談

  • 事業KPIに即したGA4に取り込むべきイベント設計/GTM設定

  • サーバーサイドGTMの導入

  • ADH, AMCをはじめとするData Crean Roomを用いた各種分析とインサイトの発見

  • 社内の1st Partyデータを一元管理できるダッシュボード作成

  • 広告効果検証用ダッシュボード作成


などなど、データ領域のご相談を幅広く承っております。

 

ここまで読んでいただきありがとうございました!😊

 


💡まずはお気軽にご相談ください

DataDigは、自社データをどう活かすかという戦略設計~データ活用実装まで伴走型でご支援します。御社の現状や課題に合わせた最適なデータ活用方法を一緒に検討いたします。ぜひお気軽にご相談ください。

[無料で相談してみる]

 


📣CARTA ZEROが提供する統合デジタルマーケティングサービスの全容、また現状のデジタルマーケティング施策のノウハウを認識されたい場合は、ぜひ近日オープンした「KnowHowNow」をご覧ください。

 

KnowHowNow(ノウハウナウ)はこちらから

#BigQuery

  • #GA4連携
  • #GA4/分析
  • #Google アナリティクス4

    データ分析のお悩みや課題を
    CARTA ZEROが解決します。

    CARTA ZEROのAnalyticsサービスでは戦略・KPIの設定や分析設計、ツール導入・運用サポートまで総合的に支援します。
    経験豊富なアナリストが
    貴社をご支援
    お問い合わせは
    こちら

    CARTA ZEROは、100以上のWebサイト支援実績を有しています

    CARTA ZERO Analyticsサービス
    支援企業様例

    ※50音順で掲載しています

    CARTA ZEROは、Google社よりAnalytics認定パートナー(GMP Partner)を取得しています。また、Adobe社のマーケティングソリューションパートナーとしても活動中です。これまでにECサイト・リード獲得サイト・ブランド認知サイトと、多種多様なお客様運営サイトの実装・分析・BIダッシュボード開発を手掛けています。