
Fivetran Activations で Snowflake の VARCHAR 列を Amazon S3 に CSV 出力すると先頭ゼロは消えるのか試してみた
かわばたです。
本記事では、先頭ゼロ付きの VARCHAR 列を持つ Snowflake のテーブルを Fivetran Activations で S3 に出力します。CSV / TSV / Parquet の 3 形式でファイルの中身を確認します。
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 が書き出す時点か、ファイルを開くソフトが読み込む時点のどちらかです。本記事では前者を、ファイルをテキストとして直接見ることで確かめます。
前提条件
- 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 で確認しました。
型の扱いはドキュメントに書かれていないため、実機で確かめてから設計に反映するのが確実です。
この記事が何かの参考になれば幸いです!





