Fivetran Activations で Snowflake の VARCHAR 列を Amazon S3 に CSV 出力すると先頭ゼロは消えるのか試してみた

Fivetran Activations で Snowflake の VARCHAR 列を Amazon S3 に CSV 出力すると先頭ゼロは消えるのか試してみた

Fivetran Activations を使って、Snowflake の先頭ゼロ付き VARCHAR 列を S3 に出力する際、CSV / TSV / Parquet の 3 形式でデータがどう扱われるかを実検証してみました。
2026.11.07

かわばたです。

本記事では、先頭ゼロ付きの VARCHAR 列を持つ Snowflake のテーブルを Fivetran Activations で S3 に出力します。CSV / TSV / Parquet の 3 形式でファイルの中身を確認します。

https://fivetran.com/docs/activations/destinations/available-destinations/s3

https://fivetran.com/docs/activations/sources/available-sources/snowflake

Fivetran Activations の S3 出力の概要

Fivetran Activations は、データウェアハウスのテーブルや SQL の結果を SaaS やストレージへ送るリバース ETL の機能です。Snowflake を activation source、Amazon S3 を activation destination として使います。

S3 destination の出力形式は 5 種類です。

形式 内容
CSV 区切り文字を変更可。ヘッダー行の有無を選べる
TSV タブ区切り。ヘッダー行の有無を選べる
JSON 1 つの JSON 配列
NDJSON 改行区切りの JSON オブジェクト
Parquet 列指向フォーマット

公式ドキュメントでは、設定した区切り文字を含む値は二重引用符で囲まれると説明されています。引用符や改行を含む値の扱いは、実際の出力で確認します。ファイル名には %yyyy %m %d などの変数を使えます。

参照した Snowflake source と S3 destination の公式ページには、列の型の対応表は見当たりませんでした。Fivetran サポートの回答(2026年11月5日)では次のとおりです。

  • Activations は値の内容から型を推論しない。Snowflake の列メタデータにある宣言型を使う
  • DATE、TIME、BINARY、VARIANT、OBJECT、ARRAY、GEOGRAPHY は String になる。「Unsupported column type will be treated as text」の警告が出る
  • Parquet 出力では文字列の先頭ゼロを保持する

CSV という形式自体には、先頭ゼロを削る規則はありません。先頭ゼロが消えるとすれば、Activations が書き出す時点か、ファイルを開くソフトが読み込む時点のどちらかです。本記事では前者を、ファイルをテキストとして直接見ることで確かめます。

https://www.rfc-editor.org/rfc/rfc4180

前提条件

  • Fivetran アカウントで Activations が使えること
  • Snowflake アカウント(本記事は Enterprise の trial アカウント、AWS ap-northeast-1)
  • Activations から Snowflake に接続するサービスユーザー。本記事は TYPE = SERVICE で作るため、パスワードではログインできず key-pair 認証を使います
  • S3 バケットと、バケットへ書き込める IAM ユーザーのアクセスキー(または IAM ロール)

Sync Engine は Basic を選びます。Basic は読み取り権限だけで動き、Snowflake 側に CENSUS データベースを作らずに済みます。Advanced を選ぶと CENSUS データベースへの書き込み権限が要ります。

事前準備

Snowflake 側: 検証テーブルとサービスユーザー

先頭ゼロ付きの文字列列と、同じ値を数値で持つ列を並べたテーブルを作ります。区切り文字や引用符を含む文字列、NULL、空文字、DATE / TIMESTAMP / BOOLEAN / VARIANT も入れて、CSV での表現を一度に見ます。

事前準備
USE ROLE ACCOUNTADMIN;

CREATE DATABASE IF NOT EXISTS ACTIVATIONS_DEMO;
CREATE WAREHOUSE IF NOT EXISTS ACTIVATIONS_WH
  WITH WAREHOUSE_SIZE = XSMALL AUTO_SUSPEND = 60 AUTO_RESUME = TRUE INITIALLY_SUSPENDED = TRUE;

CREATE OR REPLACE TABLE ACTIVATIONS_DEMO.PUBLIC.LEADING_ZERO_TEST (
  ID               NUMBER(38,0) NOT NULL,
  POSTAL_CODE      VARCHAR(7),      -- 先頭ゼロ付き 7 桁(文字列)
  POSTAL_CODE_NUM  NUMBER(7,0),     -- 同じ値を数値で保持(比較用)
  EMP_CODE         VARCHAR(5),      -- 先頭ゼロ付き・英字混在のコード
  NOTE             VARCHAR(100),    -- 区切り文字・引用符を含む文字列
  AMOUNT           NUMBER(10,2),
  EVENT_DATE       DATE,
  EVENT_TS         TIMESTAMP_NTZ,
  IS_ACTIVE        BOOLEAN,
  ATTRS            VARIANT
);

INSERT INTO ACTIVATIONS_DEMO.PUBLIC.LEADING_ZERO_TEST
SELECT 1, '0600001', 600001,  '00042', 'Sapporo',       1234.50, '2026-11-01'::DATE, '2026-11-01 09:00:00'::TIMESTAMP_NTZ, TRUE,  OBJECT_CONSTRUCT('zip', '0600001')
UNION ALL
SELECT 2, '1000001', 1000001, 'A0042', 'Hello, world',  0.10,    '2026-11-02'::DATE, '2026-11-02 18:30:15'::TIMESTAMP_NTZ, FALSE, OBJECT_CONSTRUCT('zip', '1000001')
UNION ALL
SELECT 3, '0010000', 10000,   '00100', 'say "hi"',      NULL,    NULL,               NULL,                                 NULL,  NULL
UNION ALL
SELECT 4, NULL,      NULL,    '',      '',              100.00,  '2026-11-04'::DATE, '2026-11-04 00:00:00'::TIMESTAMP_NTZ, TRUE,  OBJECT_CONSTRUCT_KEEP_NULL('zip', NULL)
UNION ALL
SELECT 5, '0000000', 0,       '00000', 'all zeros',     0.00,    '2026-11-05'::DATE, '2026-11-05 23:59:59'::TIMESTAMP_NTZ, FALSE, OBJECT_CONSTRUCT();

投入したデータは次のとおりです。

ID POSTAL_CODE POSTAL_CODE_NUM EMP_CODE NOTE AMOUNT EVENT_DATE IS_ACTIVE ATTRS
1 0600001 600001 00042 Sapporo 1234.50 2026-11-01 TRUE {"zip":"0600001"}
2 1000001 1000001 A0042 Hello, world 0.10 2026-11-02 FALSE {"zip":"1000001"}
3 0010000 10000 00100 say "hi" NULL NULL NULL NULL
4 NULL NULL (空文字) (空文字) 100.00 2026-11-04 TRUE {"zip":null}
5 0000000 0 00000 all zeros 0.00 2026-11-05 FALSE {}

Activations が使う読み取り専用ロールとサービスユーザーを作ります。Fivetran の Snowflake source ドキュメントの構成に合わせています。

CREATE ROLE IF NOT EXISTS ACTIVATIONS_ROLE;
GRANT ROLE ACTIVATIONS_ROLE TO ROLE SYSADMIN;
GRANT USAGE, OPERATE, MONITOR ON WAREHOUSE ACTIVATIONS_WH TO ROLE ACTIVATIONS_ROLE;
GRANT USAGE ON DATABASE ACTIVATIONS_DEMO TO ROLE ACTIVATIONS_ROLE;
GRANT USAGE ON SCHEMA ACTIVATIONS_DEMO.PUBLIC TO ROLE ACTIVATIONS_ROLE;
GRANT SELECT ON ALL TABLES IN SCHEMA ACTIVATIONS_DEMO.PUBLIC TO ROLE ACTIVATIONS_ROLE;
GRANT SELECT ON FUTURE TABLES IN SCHEMA ACTIVATIONS_DEMO.PUBLIC TO ROLE ACTIVATIONS_ROLE;

CREATE USER IF NOT EXISTS ACTIVATIONS_USER
  TYPE = SERVICE
  DEFAULT_ROLE = ACTIVATIONS_ROLE
  DEFAULT_WAREHOUSE = ACTIVATIONS_WH;
GRANT ROLE ACTIVATIONS_ROLE TO USER ACTIVATIONS_USER;

key pair の生成と公開鍵の登録

Activations の Snowflake source は key-pair 認証を推奨しています。Git for Windows に含まれる openssl で鍵を作ります。

& "C:\Program Files\Git\usr\bin\openssl.exe" genrsa 2048 | & "C:\Program Files\Git\usr\bin\openssl.exe" pkcs8 -topk8 -inform PEM -out rsa_key.p8 -nocrypt
& "C:\Program Files\Git\usr\bin\openssl.exe" rsa -in rsa_key.p8 -pubout -out rsa_key.pub

rsa_key.pub の BEGIN / END 行を除いた本文を、サービスユーザーに登録します。

ALTER USER ACTIVATIONS_USER SET RSA_PUBLIC_KEY = 'MIIBIjANBgkqh...';
DESC USER ACTIVATIONS_USER;  -- RSA_PUBLIC_KEY_FP に値が入れば登録済み

S3 側: バケットと IAM ユーザー

検証用のバケットを 1 つ作り、書き込み用の IAM ユーザーにアクセスキーを発行します。必要な権限は Fivetran のドキュメントの例に合わせます。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:ListBucket",
        "s3:AbortMultipartUpload",
        "s3:ListMultipartUploadParts",
        "s3:ListBucketMultipartUploads"
      ],
      "Resource": [
        "arn:aws:s3:::<バケット名>",
        "arn:aws:s3:::<バケット名>/*"
      ]
    }
  ]
}

試してみた

Snowflake を activation source として登録する

Fivetran の管理画面で Activations の Sources から New Source を選び、Snowflake を登録します。

  • Snowflake Account Name: 接続 URL の先頭(<組織名>-<アカウント名>)
  • Query Execution Warehouse: ACTIVATIONS_WH
  • User: ACTIVATIONS_USER
  • Role: ACTIVATIONS_ROLE
  • Authentication: Key-pair。rsa_key.p8 の内容をヘッダー・フッター込みで貼る
  • Sync Engine: Basic

S3 を activation destination として登録する

Destinations から Amazon S3 を選び、Access Key ID、Secret Key、Bucket Name、AWS Region を入れて保存します。接続テストで s3:PutObject などの権限が検査されます。

CSV で sync を作って実行する

Add activation で source に Snowflake、destination に S3 を選び、activation sync を作ります。

  • Source: ACTIVATIONS_DEMO.PUBLIC.LEADING_ZERO_TEST
  • Sync behavior: Update or Create
  • Sync key: ID
  • Field mappings: Sync All Columns
  • File Path: csv/leading_zero_test_%yyyy%m%d.csv
  • Advanced Configuration: File format は CSV、ヘッダー行あり

field mapping の画面では、各列に Activations が付けた型が表示されます。VARCHAR 列が String、NUMBER(38,0) が Integer、VARIANT が Strinになっていることを確認します。

手動でデータ型変換も可能なようです。

セットアップが完了しました。

CSV の中身を確認する

S3 からファイルをダウンロードし、テキストとしてそのまま表示します。

aws s3 cp s3://<バケット名>/csv/ C:\work\ --recursive
Get-Content C:\work\leading_zero_test_20261106_full.csv
unique_id,ID,POSTAL_CODE,POSTAL_CODE_NUM,EMP_CODE,NOTE,AMOUNT,EVENT_DATE,EVENT_TS,IS_ACTIVE,ATTRS
1,1,0600001,600001,00042,Sapporo,1234.5,2026-11-01,2026-11-01T09:00:00.000+00:00,true,"{
  ""zip"": ""0600001""
}"
2,2,1000001,1000001,A0042,"Hello, world",0.1,2026-11-02,2026-11-02T18:30:15.000+00:00,false,"{
  ""zip"": ""1000001""
}"
3,3,0010000,10000,00100,"say ""hi""",,,,,
4,4,,,"","",100.0,2026-11-04,2026-11-04T00:00:00.000+00:00,true,"{
  ""zip"": null
}"
5,5,0000000,0,00000,all zeros,0.0,2026-11-05,2026-11-05T23:59:59.000+00:00,false,{}

読み取れることは次のとおりです。

  • POSTAL_CODE と EMP_CODE の先頭ゼロは全行で残りました。値は 0600001 / 0010000 / 0000000 と 00042 / 00100 / 00000 です。
  • 先頭に unique_id 列が追加されます。sync key に指定した ID の値が入ります
  • カンマ、引用符、改行を含む値は二重引用符で囲まれ、内側の " は "" に二重化されます("Hello, world"、"say ""hi""")。{} のように特殊文字を含まない値は囲まれません
  • NULL は空欄、空文字は "" です。両者は区別できます
  • NUMBER(10,2) は末尾のゼロが落ちます(1234.50 → 1234.5、0.00 → 0.0)
  • DATE は 2026-11-01、TIMESTAMP_NTZ は 2026-11-01T09:00:00.000+00:00 で、ミリ秒 3 桁と +00:00 が付きます。BOOLEAN は true / false です
  • VARIANT は改行と 2 スペースのインデント付きで整形された JSON になり、値全体が引用符で囲まれます。CSV の 1 レコードが複数行にまたがります

CSV のテキストに先頭ゼロが残っているので、ゼロが消えるとすればファイルを読み込む側の処理です。

TSV で出力する

sync を複製して File Path を tsv/leading_zero_test_%yyyy%m%d.tsv、File format を TSV に変えて実行します。ダウンロードと確認の手順は CSV と同じです。

2026年11月7日に出力した TSV の全文です。区切りのタブは見た目では空白と区別が付かないので、そのまま貼っています。

unique_id	ID	POSTAL_CODE	POSTAL_CODE_NUM	EMP_CODE	NOTE	AMOUNT	EVENT_DATE	EVENT_TS	IS_ACTIVE	ATTRS
1	1	0600001	600001	00042	Sapporo	1234.5	2026-11-01	2026-11-01T09:00:00.000+00:00	true	"{
  ""zip"": ""0600001""
}"
2	2	1000001	1000001	A0042	Hello, world	0.1	2026-11-02	2026-11-02T18:30:15.000+00:00	false	"{
  ""zip"": ""1000001""
}"
3	3	0010000	10000	00100	"say ""hi"""					
4	4			""	""	100.0	2026-11-04	2026-11-04T00:00:00.000+00:00	true	"{
  ""zip"": null
}"
5	5	0000000	0	00000	all zeros	0.0	2026-11-05	2026-11-05T23:59:59.000+00:00	false	{}

CSV と違う点は 1 つだけです。Hello, world が囲まれません。区切り文字がタブなので、カンマは特殊文字ではなくなります。say "hi" と VARIANT の JSON は、引用符と改行を含むため CSV と同じく囲まれます。

先頭ゼロ、unique_id 列、NULL と空文字の表現、小数・日時・BOOLEAN の書式は CSV と同じでした。

Parquet で出力する

File Path を parquet/leading_zero_test_%yyyy%m%d.parquet、File format を Parquet に変えて実行します。Parquet はテキストでは読めないので、Snowflake の内部ステージに置いて中身を見ます。INFER_SCHEMA の出力は Snowflake が解釈したデータ型で、Activations 内部の型名ではありません。値は $1 で見ます。

aws s3 cp s3://<バケット名>/parquet/ C:\work\ --recursive
snow stage copy "C:\work\leading_zero_test_20261106_full.parquet" "@ACTIVATIONS_DEMO.PUBLIC.OUTPUT_STAGE" -c trial --overwrite
CREATE OR REPLACE FILE FORMAT ACTIVATIONS_DEMO.PUBLIC.FF_PARQUET TYPE = PARQUET;

-- 出力された Parquet を Snowflake が解釈した列の型
SELECT COLUMN_NAME, TYPE, NULLABLE
FROM TABLE(INFER_SCHEMA(
  LOCATION    => '@ACTIVATIONS_DEMO.PUBLIC.OUTPUT_STAGE/leading_zero_test_20261106_full.parquet',
  FILE_FORMAT => 'ACTIVATIONS_DEMO.PUBLIC.FF_PARQUET'));

-- 値
SELECT $1
FROM @ACTIVATIONS_DEMO.PUBLIC.OUTPUT_STAGE/leading_zero_test_20261106_full.parquet
  (FILE_FORMAT => 'ACTIVATIONS_DEMO.PUBLIC.FF_PARQUET');

2026年11月7日に出力した Parquet を INFER_SCHEMA で読んだ結果です。列の並びはファイル内の順(Source Order)です。

COLUMN_NAME TYPE NULLABLE
unique_id TEXT TRUE
ID NUMBER(38, 0) TRUE
POSTAL_CODE TEXT TRUE
POSTAL_CODE_NUM NUMBER(38, 0) TRUE
EMP_CODE TEXT TRUE
NOTE TEXT TRUE
AMOUNT NUMBER(38, 10) TRUE
EVENT_DATE TEXT TRUE
EVENT_TS TIMESTAMP_NTZ TRUE
IS_ACTIVE BOOLEAN TRUE
ATTRS TEXT TRUE

$1 の値です。Snowsight は VARIANT のキーをアルファベット順に表示し、NULL のキーは省きます。代表的な 1、3、4 行目を載せます。

{
  "AMOUNT": 1234.5,
  "ATTRS": "{\n  \"zip\": \"0600001\"\n}",
  "EMP_CODE": "00042",
  "EVENT_DATE": "2026-11-01",
  "EVENT_TS": "2026-11-01 09:00:00.000",
  "ID": 1,
  "IS_ACTIVE": true,
  "NOTE": "Sapporo",
  "POSTAL_CODE": "0600001",
  "POSTAL_CODE_NUM": 600001,
  "unique_id": "1"
}
{
  "EMP_CODE": "00100",
  "ID": 3,
  "NOTE": "say \"hi\"",
  "POSTAL_CODE": "0010000",
  "POSTAL_CODE_NUM": 10000,
  "unique_id": "3"
}
{
  "AMOUNT": 100,
  "ATTRS": "{\n  \"zip\": null\n}",
  "EMP_CODE": "",
  "EVENT_DATE": "2026-11-04",
  "EVENT_TS": "2026-11-04 00:00:00.000",
  "ID": 4,
  "IS_ACTIVE": true,
  "NOTE": "",
  "unique_id": "4"
}

2 行目と 5 行目も同じ形で、POSTAL_CODE は "1000001" と "0000000"、EMP_CODE は "A0042" と "00000" でした。

読み取れることは次のとおりです。

  • POSTAL_CODE と EMP_CODE は TEXT 列になり、先頭ゼロは全行で残りました。サポート回答の「Parquet は先頭ゼロを保持する」のとおりです
  • unique_id は TEXT で、値は "1" のような文字列です。CSV / TSV では数値と見分けが付きませんでしたが、Parquet では文字列だと分かります
  • AMOUNT は Snowflake が NUMBER(38, 10) と解釈しました。値の表示は 1234.5 / 100 / 0 で、末尾のゼロは出ません
  • EVENT_DATE は TEXT("2026-11-01")、EVENT_TS は TIMESTAMP_NTZ(2026-11-01 09:00:00.000)です。CSV / TSV と違い +00:00 は付きません
  • IS_ACTIVE は BOOLEAN、ATTRS は TEXT です。ATTRS の中身は CSV と同じ改行入りの整形 JSON が文字列として入ります
  • NULL は null、空文字は "" で、両者は区別できます

結果のまとめ

列 Snowflake の型 CSV TSV Parquet
POSTAL_CODE(0600001) VARCHAR(7) 0600001(保持) 0600001(保持) TEXT "0600001"(保持)
EMP_CODE(00042) VARCHAR(5) 00042(保持) 00042(保持) TEXT "00042"(保持)
POSTAL_CODE_NUM(600001) NUMBER(7,0) 600001 600001 NUMBER(38, 0) 600001
NOTE(Hello, world) VARCHAR(100) "Hello, world"(引用符で囲む) Hello, world(囲まない) TEXT "Hello, world"
NULL / 空文字 - 空欄 / "" 空欄 / "" null / ""
AMOUNT(1234.50) NUMBER(10,2) 1234.5(末尾ゼロが落ちる) 1234.5 NUMBER(38, 10) 1234.5
EVENT_TS TIMESTAMP_NTZ 2026-11-01T09:00:00.000+00:00 同左 TIMESTAMP_NTZ 2026-11-01 09:00:00.000
ATTRS VARIANT 整形 JSON(複数行、引用符で囲む) 同左 TEXT(整形 JSON の文字列)
unique_id(追加列) - 1 1 TEXT "1"

Parquet 列の型は、Snowflake の INFER_SCHEMA が解釈した型です。

制限事項・注意点

  • Activations の列の型の扱いは、2026年11月5日時点の Fivetran サポートの回答に基づいています。参照した Snowflake source / S3 destination の公式ページでは対応表を確認できませんでした。挙動は変わる可能性があります
  • 数値型では、コードとしての先頭ゼロや桁数は保持されません。先頭ゼロが必要な列は、出力元の Snowflake で文字列として用意します。既に数値になった値は、VARCHAR に変換しても元の先頭ゼロは戻りません
  • Basic Sync Engine から Advanced への切り替えは coming soon、Advanced から Basic へは戻せません(ドキュメント記載)

最後に

Snowflake の VARCHAR 列を Fivetran Activations で S3 に出力したときの先頭ゼロの扱いを、CSV / TSV / Parquet で確認しました。
型の扱いはドキュメントに書かれていないため、実機で確かめてから設計に反映するのが確実です。

この記事が何かの参考になれば幸いです!


Fivetranの導入支援はクラスメソッドにおまかせください

クラスメソッドはFivetranのライセンス販売パートナーです。
FivetranのほかにもAWS、Looker、Alteryx、Tableau、Snowflakeとパートナー契約を結んでおり、それぞれ豊富な導入実績があります。各サービスとFivetranを連携させることで、お客様の環境にあわせた最適な構成をご提案します。
Fivetranの導入支援の詳細を見る

この記事をシェアする

関連記事