
はじめに
データドリブンな人間を目指している香取です。
Snowflake を使っていると、データのアップロード時に「内部ステージ」「外部ステージ」という概念に出会うことがあります。
どちらがどう違って、どのように使い分けるのか、理解できていなかったので、簡単にステージについて整理してみました。
Snowflake のステージとは
ステージ (Stage) とは、Snowflake にデータをロードする前の一時的な保存場所のことです。 データベースに直接データを投入するのではなく、まずはステージという中間的な場所にデータを置いてから、COPY INTO <テーブル> コマンドで Snowflake のテーブルにロードします。
ステージには以下の 2 種類があります
- 内部ステージ (Internal Stage) : Snowflake アカウント内で管理されるストレージ
- 外部ステージ (External Stage) : Amazon S3 などの Snowflake アカウント外のクラウドストレージ

内部ステージ概要
内部ステージは、Snowflake アカウント内で管理されるストレージです。 主にローカルマシンから直接ファイルをアップロードしたい場合に使用します。
内部ステージは 3 種類あります。(公式ドキュメント)
基本的には自動で作成されるユーザーステージかテーブルステージを使い、複数ユーザーで共有する & 複数テーブルにデータをロードしたい場合は名前付きステージを作成して使用するようなイメージです。

ユーザーステージ
- Snowflake ユーザーごとに自動で作成される専用ステージ
- 単一のユーザーのみステージング可能
- 複数のテーブルにデータをロードできる
- Snowflake 管理ステージのため変更や削除はできない
テーブルステージ
- Snowflake で作成されたテーブルごとに自動で作成されるステージ
- 複数ユーザーがステージング可能
- 単一のテーブルにのみデータをロードできる
- Snowflake 管理ステージのため変更や削除はできない
名前付きステージ
- ユーザーが任意で作成するステージ (CREATE STAGE コマンドを使用)
- 複数ユーザーがステージング可能
- 複数のテーブルにデータをロードできる
- ステージに対する権限があれば作成、変更、削除が可能
外部ステージ概要
外部ステージは Amazon S3 などの外部クラウドストレージを指します。 Amazon S3 などの外部クラウドストレージから直接 Snowflake にデータをロードしたい場合や、複数の Snowflake アカウント間でデータを共有したい場合に使用します。

外部ステージに使用できるクラウドストレージ
外部ステージには以下のクラウドストレージが使用できます。(公式ドキュメント)
- Amazon S3
- Google Cloud Storage
- Microsoft Azure Blob Storage
内部ステージを使ってデータをアップロードしてみる
実際に名前付きステージを使ってローカルの CSV ファイルをアップロードしてみます。
ここでは名前付きステージを使用していますが、ユーザーステージやテーブルステージでも同様の手順でデータをアップロードできます。(公式ドキュメント)
また、コマンドは SnowSQL を使用してローカル環境から実行しています。SnowSQL のインストール方法については 公式ドキュメント や下記の記事を参照してください。
クリックすると展開します
step1. サンプルデータの準備
まず、以下のような sample_data.csv ファイルを用意します
id,name,age,city 1,田中太郎,25,東京 2,佐藤花子,30,大阪 3,鈴木次郎,28,名古屋
step2. データベースとテーブルの作成
事前に使用するデータベースとテーブルを作成しておきます。
$ <username>#COMPUTE_WH@(no database).(no schema)>CREATE DATABASE STAGE_TEST_DB; +----------------------------------------------+ | status | |----------------------------------------------| | Database STAGE_TEST_DB successfully created. | +----------------------------------------------+ 1 Row(s) produced. Time Elapsed: 0.172s
$ <username>#COMPUTE_WH@STAGE_TEST_DB.PUBLIC>USE DATABASE STAGE_TEST_DB; +----------------------------------+ | status | |----------------------------------| | Statement executed successfully. | +----------------------------------+ 1 Row(s) produced. Time Elapsed: 0.051s
$ <username>#COMPUTE_WH@STAGE_TEST_DB.PUBLIC>CREATE TABLE USERS_INTERNAL ( ID INT, NAME STRING, AGE INT, CITY STRING ); +-----------------------------------+ | status | |-----------------------------------| | Table USERS_INTERNAL successfully created. | +-----------------------------------+ 1 Row(s) produced. Time Elapsed: 0.214s
step3. 名前付きステージの作成
名前付きステージは自分で作成する必要があるため、CREATE STAGE コマンドでステージを作成します。
$ <username>#COMPUTE_WH@STAGE_TEST_DB.PUBLIC>CREATE STAGE INTERNAL_NAMED_STAGE_TEST FILE_FORMAT = (TYPE = 'CSV' FIELD_DELIMITER = ',' SKIP_HEADER = 1); +------------------------------------------------------------+ | status | |------------------------------------------------------------| | Stage area INTERNAL_NAMED_STAGE_TEST successfully created. | +------------------------------------------------------------+ 1 Row(s) produced. Time Elapsed: 0.119s
step4. 名前付きステージへのファイルアップロード (ステージング)
内部ステージにファイルをアップロードするには、PUT コマンドを使用します。(公式ドキュメント)
./sample_data.csv ファイルを Snowflake の名前付きステージにアップロードする例を示します。
$ <username>#COMPUTE_WH@STAGE_TEST_DB.PUBLIC>PUT file://./sample_data.csv @INTERNAL_NAMED_STAGE_TEST; +-----------------+--------------------+-------------+-------------+--------------------+--------------------+----------+---------+ | source | target | source_size | target_size | source_compression | target_compression | status | message | |-----------------+--------------------+-------------+-------------+--------------------+--------------------+----------+---------| | sample_data.csv | sample_data.csv.gz | 95 | 144 | NONE | GZIP | UPLOADED | | +-----------------+--------------------+-------------+-------------+--------------------+--------------------+----------+---------+ 1 Row(s) produced. Time Elapsed: 0.389s
step5. ステージ内のファイル確認
アップロードしたファイルがステージに正しく保存されているか確認します。
$ <username>#COMPUTE_WH@STAGE_TEST_DB.PUBLIC>LIST @INTERNAL_NAMED_STAGE_TEST; +----------------------------------------------+------+----------------------------------+------------------------------+ | name | size | md5 | last_modified | |----------------------------------------------+------+----------------------------------+------------------------------| | internal_named_stage_test/sample_data.csv.gz | 144 | 562eef0761884b8bd1d09482dc60c932 | Sun, 6 Jul 2025 22:37:05 GMT | +----------------------------------------------+------+----------------------------------+------------------------------+ 1 Row(s) produced. Time Elapsed: 0.108s
step6. テーブルへのデータロード
COPY INTO <テーブル> コマンドを使用して、名前付きステージにアップロードしたファイルをテーブルにロードします。
-- ステージから USERS_INTERNAL テーブルにデータをロード $ <username>#COMPUTE_WH@STAGE_TEST_DB.PUBLIC>COPY INTO USERS_INTERNAL FROM @INTERNAL_NAMED_STAGE_TEST/sample_data.csv.gz FILE_FORMAT = (TYPE = 'CSV' FIELD_DELIMITER = ',' SKIP_HEADER = 1); +----------------------------------------------+--------+-------------+-------------+-------------+-------------+-------------+------------------+-----------------------+-------------------------+ | file | status | rows_parsed | rows_loaded | error_limit | errors_seen | first_error | first_error_line | first_error_character | first_error_column_name | |----------------------------------------------+--------+-------------+-------------+-------------+-------------+-------------+------------------+-----------------------+-------------------------| | internal_named_stage_test/sample_data.csv.gz | LOADED | 3 | 3 | 1 | 0 | NULL | NULL | NULL | NULL | +----------------------------------------------+--------+-------------+-------------+-------------+-------------+-------------+------------------+-----------------------+-------------------------+ 1 Row(s) produced. Time Elapsed: 0.758s
-- データが正しくロードされたか確認 $ <username>#COMPUTE_WH@STAGE_TEST_DB.PUBLIC>SELECT * FROM USERS_INTERNAL; +----+----------+-----+--------+ | ID | NAME | AGE | CITY | |----+----------+-----+--------| | 1 | 田中太郎 | 25 | 東京 | | 2 | 佐藤花子 | 30 | 大阪 | | 3 | 鈴木次郎 | 28 | 名古屋 | +----+----------+-----+--------+
外部ステージを使ってデータをアップロードしてみる
Amazon S3 上の CSV ファイルを外部ステージを使って Snowflake にロードしてみます。
クリックすると展開します
step1. データの準備
「内部ステージを使ってデータをアップロードしてみる」の「1. サンプルデータの準備」で使用した CSV ファイルを S3 バケットにアップロードし、「2. データベースとテーブルの作成」と同様の手順で、データベースとテーブル (USERS_EXTERNAL) を作成しておきます。
step2. IAM ポリシーの作成
S3 バケットのある AWS アカウントで以下の IAM ポリシーを作成します。(公式ドキュメント)
{ "Version": "2012-10-17", "Statement": [ { "Effect":"Allow", "Action":[ "s3:PutObject", "s3:GetObject", "s3:GetObjectVersion", "s3:DeleteObject", "s3:DeleteObjectVersion" ], "Resource": "arn:aws:s3:::<bucket>/<prefix>/*" }, { "Effect":"Allow", "Action":[ "s3:ListBucket", "s3:GetBucketLocation" ], "Resource":"arn:aws:s3:::<bucket>", } ] }
step3. IAM ロールの作成
以下の条件で、作成した IAM ポリシーを適用する IAM ロールを作成します。(公式ドキュメント)
- 信頼されたエンティティタイプ : AWS アカウント
- AWS アカウント : 別の AWS アカウント
- アカウント ID : 自分の AWS アカウント ID を一時的に入力します。後で、信頼関係を変更し、Snowflake へのアクセスを許可します。
- オプション : 「外部 ID を要求する」にチェックをいれます
- 外部 ID : 0000 などのダミー ID を入力します。後で、 IAM ロールの信頼関係を変更し、ストレージ統合の外部 ID を指定します。
- AWS アカウント : 別の AWS アカウント
- 許可を追加
- 先ほど作成した IAM ポリシーを選択します
- ロール名を指定し、ロールを作成します
step4. ストレージ統合の作成
Snowflake で外部ステージを使用するために、CREATE STORAGE INTEGRATION コマンドでストレージ統合を作成します。
$ <username>#COMPUTE_WH@STAGE_TEST_DB.PUBLIC>CREATE STORAGE INTEGRATION S3_INTEGRATION TYPE = EXTERNAL_STAGE STORAGE_PROVIDER = 'S3' ENABLED = TRUE STORAGE_AWS_ROLE_ARN = '<作成した IAM ロールの ARN>' STORAGE_ALLOWED_LOCATIONS = ('<s3://your-bucket-name>/<path>/'); +--------------------------------------------------+ | status | |--------------------------------------------------| | Integration S3_INTEGRATION successfully created. | +--------------------------------------------------+ 1 Row(s) produced. Time Elapsed: 0.229s
step5. Snowflake が使用する AWS の IAM ユーザーと外部 ID を取得する
DESC INTEGRATION を実行し、Snowflake が使用する AWS の IAM ユーザーと外部 ID を取得します。
$ <username>#COMPUTE_WH@STAGE_TEST_DB.PUBLIC>DESC INTEGRATION S3_INTEGRATION; +---------------------------+---------------+--------------------------------------------------------------+------------------+ | property | property_type | property_value | property_default | |---------------------------+---------------+--------------------------------------------------------------+------------------| ~略~ | STORAGE_AWS_IAM_USER_ARN | String | arn:aws:iam::xxxxxxxxxxxx:user/xxxxxxxx-x | | ~略~ | STORAGE_AWS_EXTERNAL_ID | String | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | | ~略~
step6. IAM ロールの信頼ポリシーを更新する
先ほど取得した「Snowflake が使用する AWS の IAM ユーザーの ARN (STORAGE_AWS_IAM_USER_ARN)」と「外部 ID (STORAGE_AWS_EXTERNAL_ID)」を使って、IAM ロールの信頼ポリシーを更新します。(公式ドキュメント)
これにより、Snowflake がこの IAM ロールを使用して S3 バケットへアクセスできるようになります。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "<STORAGE_AWS_IAM_USER_ARN の値を入力>" }, "Action": "sts:AssumeRole", "Condition": { "StringEquals": { "sts:ExternalId": "<STORAGE_AWS_EXTERNAL_ID の値を入力>" } } } ] }
step7. 外部ステージの作成
CREATE STAGE コマンドを使用して、外部ステージを作成します。ここでは、「3. Snowflake でストレージ統合を作成する」で作成したストレージ統合を使用します。
$ <username>#COMPUTE_WH@STAGE_TEST_DB.PUBLIC>CREATE STAGE EXTERNAL_NAMED_STAGE_TEST STORAGE_INTEGRATION = S3_INTEGRATION URL = 's3://<your-bucket-name>/<path>/sample_data.csv' FILE_FORMAT = (TYPE = 'CSV' FIELD_DELIMITER = ',' SKIP_HEADER = 1); +------------------------------------------------------------+ | status | |------------------------------------------------------------| | Stage area EXTERNAL_NAMED_STAGE_TEST successfully created. | +------------------------------------------------------------+ 1 Row(s) produced. Time Elapsed: 0.742s
step8. 外部ステージ内のファイル確認
LIST コマンドを使用して、外部ステージ内のファイルを確認します。
$ <username>#COMPUTE_WH@STAGE_TEST_DB.PUBLIC>LIST @EXTERNAL_NAMED_STAGE_TEST; +-----------------------------------------------------+------+----------------------------------+------------------------------+ | name | size | md5 | last_modified | |-----------------------------------------------------+------+----------------------------------+------------------------------| | s3://any-bucket-dori/snowflake-test/sample_data.csv | 95 | 92e240d8ae4010bc981a04e81611fe89 | Sun, 6 Jul 2025 22:59:35 GMT | +-----------------------------------------------------+------+----------------------------------+------------------------------+ 1 Row(s) produced. Time Elapsed: 1.187s
step9. テーブルにデータをロードする
COPY INTO <テーブル> コマンドを使用して、外部ステージからデータをロードします。
-- ステージから USERS_EXTERNAL テーブルにデータをロード $ <username>#COMPUTE_WH@STAGE_TEST_DB.PUBLIC>COPY INTO USERS_EXTERNAL FROM @EXTERNAL_NAMED_STAGE_TEST FILE_FORMAT = (TYPE = 'CSV' FIELD_DELIMITER = ',' SKIP_HEADER = 1); +-----------------------------------------------------+--------+-------------+-------------+-------------+-------------+-------------+------------------+-----------------------+-------------------------+ | file | status | rows_parsed | rows_loaded | error_limit | errors_seen | first_error | first_error_line | first_error_character | first_error_column_name | |-----------------------------------------------------+--------+-------------+-------------+-------------+-------------+-------------+------------------+-----------------------+-------------------------| | s3://any-bucket-dori/snowflake-test/sample_data.csv | LOADED | 3 | 3 | 1 | 0 | NULL | NULL | NULL | NULL | +-----------------------------------------------------+--------+-------------+-------------+-------------+-------------+-------------+------------------+-----------------------+-------------------------+ 1 Row(s) produced. Time Elapsed: 1.840s
-- データが正しくロードされたか確認 $ <username>#COMPUTE_WH@STAGE_TEST_DB.PUBLIC>SELECT * FROM USERS_EXTERNAL; +----+----------+-----+--------+ | ID | NAME | AGE | CITY | |----+----------+-----+--------| | 1 | 田中太郎 | 25 | 東京 | | 2 | 佐藤花子 | 30 | 大阪 | | 3 | 鈴木次郎 | 28 | 名古屋 | +----+----------+-----+--------+ 3 Row(s) produced. Time Elapsed: 0.450s
おわりに
今回は Snowflake のステージについて、内部ステージと外部ステージの違いや使い方を整理してみました。
ポイントを再度まとめると
- Snowflake にはデータをロードする前に一時的に保存するための「ステージ」という概念がある
- ステージには「内部ステージ」と「外部ステージ」の 2 種類がある
- 内部ステージは Snowflake アカウント内で管理されるストレージであり、ローカルマシンから直接ファイルをアップロードしたい場合に使用する
- 内部ステージにはユーザーステージ、テーブルステージ、名前付きステージの 3 種類があり、用途に応じて使い分ける
- 外部ステージは Amazon S3 などのクラウドストレージから直接 Snowflake にデータをロードしたい場合や、複数の Snowflake アカウント間でデータを共有したい場合に使用する
皆さんも実際に手を動かして、ステージの使い方をマスターしてみてください!
参考
- COPY INTO | Snowflake Documentation
- データのロードの概要 | Snowflake Documentation
- CREATE STAGE | Snowflake Documentation
- ローカルファイルに対する内部ステージの選択 | Snowflake Documentation
- SnowSQL のインストールと設定 | Snowflake Documentation
- PUT | Snowflake Documentation
- 外部ステージの作成 | Snowflake Documentation
- CREATE STORAGE INTEGRATION | Snowflake Documentation
- DESC INTEGRATION | Snowflake Documentation
- LIST | Snowflake Documentation
香取 拓哉 (記事一覧)
2023年度新卒入社
データドリブンな人間を目指しています
好きな食べ物は芽ねぎ