SnowflakeはVARIANT型を中心に、JSON・Parquet・Avro・ORC・XMLといった半構造化データをリレーショナルテーブル内にネイティブに格納し、SQLで直接クエリできます。コロン表記(:)によるパスアクセス、LATERAL FLATTENによる配列展開、OBJECT_CONSTRUCT/ARRAY_AGGによる構築が試験で頻出の3大操作パターンです。
VARIANT型はJSON・オブジェクト・配列・スカラー値などあらゆる半構造化データを格納できる汎用型です。最大16MBのデータを1値に格納でき、内部的には列指向形式で圧縮保存されます。
| 半構造化型 | 格納できるデータ | 用途 |
|---|---|---|
| VARIANT | 任意の半構造化データ(JSON / オブジェクト / 配列 / スカラー) | 最も汎用的。JSONロードの受け皿 |
| OBJECT | キーバリューペアの集合 | 構造が既知のJSON Object |
| ARRAY | 順序付きの値の配列 | リスト・タグ・配列データ |
-- VARIANTカラムを持つテーブルの作成
CREATE OR REPLACE TABLE raw.events (
event_id INT AUTOINCREMENT,
received_at TIMESTAMP_NTZ DEFAULT CURRENT_TIMESTAMP(),
payload VARIANT
);
-- JSONデータの直接INSERT
INSERT INTO raw.events (payload)
SELECT PARSE_JSON('{
"user_id": 42,
"action": "purchase",
"items": [
{"sku": "A100", "qty": 2, "price": 1500},
{"sku": "B200", "qty": 1, "price": 3200}
],
"metadata": {"source": "web", "version": "2.1"}
}');VARIANT型のデータにはコロン表記(:)でキーを指定してアクセスします。ネストしたオブジェクトにはドット(.)、配列要素にはブラケット([])を使います。
-- 第1階層のキーアクセス
SELECT
payload:user_id::INT AS user_id,
payload:action::STRING AS action
FROM raw.events;
-- ネストしたオブジェクトのアクセス
SELECT
payload:metadata.source::STRING AS source,
payload:metadata.version::STRING AS api_version
FROM raw.events;
-- 配列要素へのアクセス(0始まりインデックス)
SELECT
payload:items[0].sku::STRING AS first_sku,
payload:items[0].price::NUMBER AS first_price
FROM raw.events;::(キャスト演算子)を使って明示的に型変換を行わないと、結果はVARIANT型のまま返されます。WHERE句やJOINで使用する場合は必ずキャストが必要です。
LATERAL FLATTENは、VARIANT型内の配列やオブジェクトを行に展開する関数です。JSONの配列要素を1行ずつリレーショナル形式に変換する際の標準的な手法です。
-- 配列内の各アイテムを行に展開
SELECT
e.event_id,
e.payload:user_id::INT AS user_id,
f.index AS item_index,
f.value:sku::STRING AS sku,
f.value:qty::INT AS quantity,
f.value:price::NUMBER AS price
FROM raw.events e,
LATERAL FLATTEN(INPUT => e.payload:items) f;| カラム名 | 説明 |
|---|---|
| SEQ | 入力レコードのシーケンス番号 |
| KEY | オブジェクトのキー名(配列の場合はNULL) |
| PATH | 要素へのパス文字列 |
| INDEX | 配列のインデックス(0始まり) |
| VALUE | 展開された値(VARIANT型) |
| THIS | 展開元の配列/オブジェクト全体 |
-- 2段ネストの展開(orders → items)
SELECT
o.value:order_id::INT AS order_id,
i.value:product::STRING AS product,
i.value:amount::NUMBER AS amount
FROM raw.batch_data d,
LATERAL FLATTEN(INPUT => d.payload:orders) o,
LATERAL FLATTEN(INPUT => o.value:items) i;OBJECT_CONSTRUCTは、リレーショナルカラムからVARIANT型のJSONオブジェクトを構築する関数です。データのアンロード(JSON形式でのエクスポート)やAPI連携用のペイロード生成に活用します。
-- リレーショナルデータからJSONオブジェクトを構築
SELECT OBJECT_CONSTRUCT(
'order_id', o.order_id,
'customer', o.customer_name,
'total', o.total_amount,
'order_date', o.order_date::STRING
) AS order_json
FROM analytics.orders o
WHERE o.order_date = '2026-03-27';
-- OBJECT_CONSTRUCT_KEEP_NULL(NULLキーを保持)
SELECT OBJECT_CONSTRUCT_KEEP_NULL(
'name', e.name,
'email', e.email,
'phone', e.phone
) AS employee_json
FROM hr.employees e;ARRAY_AGGは、複数行の値を1つのARRAY型に集約する関数です。GROUP BYと組み合わせて、リレーショナルデータを非正規化JSON構造に変換する際に使用します。
-- 顧客ごとの注文IDリストを配列に集約
SELECT
customer_id,
ARRAY_AGG(DISTINCT order_id) WITHIN GROUP (ORDER BY order_date)
AS order_ids,
ARRAY_SIZE(ARRAY_AGG(DISTINCT order_id)) AS order_count
FROM analytics.orders
GROUP BY customer_id;
-- OBJECT_CONSTRUCTとARRAY_AGGの組み合わせ
SELECT OBJECT_CONSTRUCT(
'customer_id', customer_id,
'orders', ARRAY_AGG(
OBJECT_CONSTRUCT(
'order_id', order_id,
'amount', total_amount
)
)
) AS customer_orders_json
FROM analytics.orders
GROUP BY customer_id;JSONファイルのロードでは、STRIP_OUTER_ARRAYオプションで最外部の配列を行に分解するパターンが頻出です。
-- JSON File Formatの定義
CREATE OR REPLACE FILE FORMAT json_format
TYPE = JSON
STRIP_OUTER_ARRAY = TRUE
ALLOW_DUPLICATE = FALSE;
-- ステージからVARIANTカラムへロード
COPY INTO raw.events (payload)
FROM @data_stage/events/
FILE_FORMAT = json_format;
-- Parquetファイルのロード(スキーマ自動検出)
COPY INTO raw.parquet_data
FROM @data_stage/parquet/
FILE_FORMAT = (TYPE = PARQUET)
MATCH_BY_COLUMN_NAME = CASE_INSENSITIVE;| 関数 | 用途 | 使用例 |
|---|---|---|
| PARSE_JSON | 文字列→VARIANT変換 | PARSE_JSON('{"key":"val"}') |
| TO_JSON | VARIANT→JSON文字列変換 | TO_JSON(payload) |
| ARRAY_SIZE | 配列の要素数を取得 | ARRAY_SIZE(payload:items) |
| ARRAY_CONTAINS | 配列内の値の存在チェック | ARRAY_CONTAINS('A100'::VARIANT, payload:skus) |
| OBJECT_KEYS | オブジェクトのキー一覧を配列で取得 | OBJECT_KEYS(payload:metadata) |
| GET_PATH / GET | パス文字列でVARIANT要素を取得 | GET_PATH(payload, 'metadata.source') |
| TYPEOF | VARIANT値の内部型を確認 | TYPEOF(payload:user_id) |
Semi-structured Data
問題 1
VARIANT型カラム payload に格納されたJSONの配列 payload:items を展開し、各要素の sku と price を取得したい。正しいSQLはどれか。
正解: A
VARIANT型内の配列を行に展開するにはLATERAL FLATTENを使用します。展開された各要素はf.valueでアクセスし、f.value:skuのようにコロン表記でキーを指定します。payload:items.skuは配列全体に対するプロパティアクセスとなり、期待した結果は得られません。SPLITは文字列分割関数であり、VARIANT配列の展開には使えません。
VARIANT型のカラムに格納できるデータサイズの上限はありますか?
VARIANT型の1つの値の最大サイズは16MBです。ただしVARIANTカラムを含むマイクロパーティション全体のサイズ制約もあるため、実運用では1レコードあたり数MB以内に収めることが推奨されます。巨大なJSONドキュメントをそのまま格納するよりも、LATERAL FLATTENで正規化して別テーブルに分解する設計が、クエリパフォーマンスとコストの両面で有利です。
VARIANT型に対するクエリはリレーショナルカラムと同等のパフォーマンスが出ますか?
SnowflakeはVARIANT型のデータを内部的に列指向形式でメタデータ(型情報・パス情報)とともに格納するため、頻繁にアクセスされるキーについては高速なアクセスが可能です。ただし、コロン表記(:)やブラケット表記([])による半構造化パスの評価はリレーショナルカラムのスキャンよりオーバーヘッドがあります。頻繁にフィルタリング・JOIN・集約に使うキーはVIEWやCTASで事前に抽出してリレーショナルカラムに変換するのがベストプラクティスです。
FLATTENでネストが深い配列を展開するにはどうしますか?
LATERAL FLATTENは1段階のネスト展開を行うため、複数段のネストには複数回のLATERAL FLATTENをチェーンします。例えばorders[].items[].tags[]のような3段ネストの場合、FROM raw, LATERAL FLATTEN(raw.data:orders) o, LATERAL FLATTEN(o.value:items) i, LATERAL FLATTEN(i.value:tags) tのように記述します。各FLATTEN結果はvalueカラムで次のFLATTENに渡せます。
NicheeLab編集部
データエンジニアリング・クラウド資格の専門家。Databricks・Snowflake等の認定資格を保有し、実務経験に基づいた問題作成・解説を行っています。NicheeLab運営。
Snowflake資格一覧|全11試験(SnowPro)の難易度・費用
Snowflake認定資格(SnowPro)全11試験の一覧・難易度・費用・出題範囲を徹底解説。...
Snowflake試験の難易度ランキング|全11資格を徹底比較
Snowflake(SnowPro)認定全11試験の難易度をランキング形式で比較。学習時間・合格に必要なスキルから分析。...
Snowflake資格の勉強方法|効率的な学習ルートと合格のコツ
Snowflake認定資格(SnowPro)に最短で合格するための勉強方法。公式リソース・学習スケジュールを徹底ガイド。...
SnowPro Core試験完全解説|出題範囲・問題例・合格戦略
SnowPro Core Certification(COF-C03)を徹底解説。出題範囲・100問の試験形式・合格ライ...
SnowPro Platform Associate完全解説|入門試験の攻略
SnowPro Associate: Platform Certification(SOL-C01)を徹底解説。最も簡単...