Azure Blob Storage を外部ステージに設定し COPY コマンドによるデータロードを試してみる #SnowflakeDB

Azure Blob Storage を外部ステージに設定し COPY コマンドによるデータロードを試してみる #SnowflakeDB

2025.10.10

はじめに

Snowflake で Azure の Blob Storage を外部ステージに設定し、COPY コマンドによる基本的なデータロードを試してみましたので、その内容をまとめてみます。

前提条件

以下の環境で検証しています。

  • Snowflake
    • クラウドサービス:Microsoft Azure
    • リージョン:japaneast
  • ストレージ アカウントのリージョン:japaneast
  • リソースグループは作成済み

Blob Storage の作成

ストレージ アカウントの作成

Azure ポータルから下図の内容でストレージ アカウントを作成しました。

image

コンテナーの追加

作成したストレージ アカウントの「ストレージ ブラウザー」メニューから「BLOB コンテナー > コンテナーの追加」をクリックします。

2025-10-09_17h19_49

下図の表示となるので、コンテナー名を指定し作成します。

image 2

作成したコンテナーの「アップロード」タブよりファイルをアップロードできます。

image 3

ストレージアカウントの「セキュリティとネットワーク > ネットワーク」メニューをクリックするとデフォルトでは下図の表示となっていました。

image 4

ここでは試しに「パブリックネットワークアクセス スコープ」を「Enabled from selected networks」に変更し、自分の接続元 IP アドレスを指定しました。

image 5

Snowflake:データロードの構成

ここから Snowflake 側もあわせて外部ステージ経由のデータロードのための構成を試してみます。

https://docs.snowflake.com/ja/user-guide/data-load-azure

VNet サブネット IDs の許可

先の手順で、このストレージ アカウントでは、特定のIPアドレスからのアクセスのみを許可するよう構成されているため、Snowflake アカウントがアクセスできるように、その VNet サブネットIDを許可リストに追加します。

https://docs.snowflake.com/ja/user-guide/data-load-azure-allow

はじめに Snowflake で以下を実行し、Snowflake アカウント側の VNet サブネット IDs を取得します。

			
			USE ROLE ACCOUNTADMIN;
SELECT SYSTEM$GET_SNOWFLAKE_PLATFORM_INFO();

		

出力は以下のようになり、ここではsnowflake-vnet-subnet-idとして/subscriptionから始まる2つのサブネット ID が返ってきました。

			
			{
	"snowflake-vnet-subnet-id":
		["/subscriptions/xxxxx",
		"/subscriptions/xxxxx"],
	"storage-account-resource-id":"/subscriptions/xxxxx"
} 

		

Azure 側で Snowflake サブネットID ごとにネットワークルールを追加します。

Azure ポータルで Cloud shell を起動し ID ごとに以下を実行します。

			
			az storage account network-rule add --resource-group "<リソースグループ名>" --account-name "<ストレージアカウント名>" --subnet "Snowflakeアカウント側のサブネットID"

		

こちらの手順は、以下を参考にしました。

https://learn.microsoft.com/en-gb/answers/questions/1840278/how-to-add-snowflake-sub-vnet-to-existing-azure-vn

設定を確認します。すでに設定済みの IP アドレスとあわせて新たに追加した Snowflake アカウント側の Vnet のサブネット ID が追加されています。

			
			$ az storage account show --name "<ストレージアカウント名>" --resource-group "<リソースグループ名>" --query 'networkRuleSet'
{
  "bypass": "AzureServices",
  "defaultAction": "Deny",
  "ipRules": [
    {
      "action": "Allow",
      "ipAddressOrRange": "xx.xx.xx.xx"
    }
  ],
  "ipv6Rules": [],
  "resourceAccessRules": [],
  "virtualNetworkRules": [
    {
      "action": "Allow",
      "state": "Succeeded",
      "virtualNetworkResourceId": "/subscriptions/xxxxx"
    },
    {
      "action": "Allow",
      "state": "Succeeded",
      "virtualNetworkResourceId": "/subscriptions/xxxxx"
    }
  ]
}

		

ストレージ統合を作成

Snowflake 側で Azure のストレージへのアクセス権を取得するためのオブジェクトとして、ストレージ統合を作成します。
この際、以下の情報が必要となるので、事前に取得・確認しておきます。

  • Microsoft Entra テナントID
  • ストレージ アカウント名
  • コンテナー名

テナント ID は、Azure ポータルの場合「Microsoft Entra ID > プロパティ > テナントID」より確認できます。

image 6

各情報を使用し、Snowflake 側でストレージ統合オブジェクトを作成します。

			
			CREATE STORAGE INTEGRATION my_azure_storage_int
  TYPE = EXTERNAL_STAGE
  STORAGE_PROVIDER = 'AZURE'
  ENABLED = TRUE
  AZURE_TENANT_ID = '<Microsoft Entra テナントID>'
  STORAGE_ALLOWED_LOCATIONS = ('azure://<ストレージアカウント名>.blob.core.windows.net/<コンテナー名>/');

		

ストレージに Snowflake アクセスを許可する

ストレージ統合を作成したら、Azure 側で Snowflake にアクセス権を付与する作業が必要です。
以下を実行し、Microsoft のアクセス許可リクエストページへの URL とアプリケーション名を取得します。

			
			DESC STORAGE INTEGRATION my_azure_storage_int;

		

出力のAZURE_CONSENT_URLが Microsoft のアクセス許可リクエストページへの URL となるので、コピーしてブラウザで開きます。
また、AZURE_MULTI_TENANT_APP_NAMEプロパティの値も後ほど使用するので控えておきます。

管理者アカウントでサインインし、「承諾」をクリックします。

image 7

image 8

承諾後は、Azure ポータルの「Microsoft Entra ID > エンタープライズ アプリケーション」より Snowflake サービスプリンシパルが作成されていることを確認できます。

image 9

続けて、Snowflake サービスプリンシパルにストレージへのアクセス権(ロール)を付与します。

Azure ポータルの対象ストレージ アカウントメニューの「アクセス制御(IAM) > 追加 > ロールの割り当ての追加」をクリックします。

image 10

各種ロールが表示されるので「Blob」等で検索フィルタし Snowflake サービスプリンシパルへの付与対象となるロールを表示します。

image 11

付与対象となるロールは、以下のいずれかです。

  • ストレージ BLOB データ閲覧者
    • 読み取りアクセスのみを許可
  • ストレージ BLOB データ共同作成者
    • 読み取りおよび書き込みアクセスを許可
    • データのロードに加え、アンロードや REMOVE コマンドによるファイルの削除も可能になります

ここでは「ストレージ BLOB データ閲覧者」を選択し、「次へ」をクリックします。「+ メンバーを選択する」をクリックし、DESC STORAGE INTEGRATIONで取得したAZURE_MULTI_TENANT_APP_NAMEアンダースコアより前の文字列を検索します。

image 12

検索結果から該当のサービスプリンシパルを選択し、ロールを割り当てます。
割り当て後は「ロールの割り当て」タブより対象のサービスプリンシパルに対して、指定のロールが割り当てられていることを確認できます。

image 13

外部ステージの作成

Azure 側の設定が完了したので、Snowflake で外部ステージを作成します。

			
			CREATE STAGE my_azure_stage
  STORAGE_INTEGRATION = my_azure_storage_int
  URL = 'azure://<ストレージアカウント名>.blob.core.windows.net/<コンテナー名>/';

		

オブジェクトを追加後、ls コマンドでステージ内のファイルを確認します。

			
			>ls @my_azure_stage;
+----------------------------------------------------------------------------------------------+------+----------------------------------+------------------------------+
| name                                                                                         | size | md5                              | last_modified                |
|----------------------------------------------------------------------------------------------+------+----------------------------------+------------------------------|
| azure://<ストレージアカウント名>.blob.core.windows.net/<コンテナー名>/sample_data_20240412.csv  |  297 | 9ac383c69c86628e39bde1e6e0fe8d7f | Thu, 9 Oct 2025 08:22:38 GMT |
+----------------------------------------------------------------------------------------------+------+----------------------------------+------------------------------+

		

サブネット ID の許可がない場合、以下のようなエラーメッセージでした。

			
			>ls @my_azure_stage;
091003 (22000): Failure using stage area. Cause: [This request is not authorized to perform this operation. (Status Code: 40                                          

		

テーブルを作成し COPY コマンドでロードしてみます。

			
			--ファイルフォーマットを作成
CREATE OR REPLACE FILE FORMAT my_csv_format
  TYPE = CSV
  FIELD_DELIMITER = ','
  PARSE_HEADER = TRUE
  EMPTY_FIELD_AS_NULL = true
  COMPRESSION = AUTO;

--スキーマ検出機能によりテーブルを定義
>CREATE OR REPLACE TABLE mytable
    USING TEMPLATE (
        SELECT ARRAY_AGG(OBJECT_CONSTRUCT(*))
        FROM TABLE(
            INFER_SCHEMA(
                LOCATION=>'@my_azure_stage/',
                FILE_FORMAT=>'my_csv_format'
                )
            )
        );
+-------------------------------------+
| status                              |
|-------------------------------------|
| Table MYTABLE successfully created. |
+-------------------------------------+

--コピーコマンドでロード
>COPY INTO mytable
	FROM @my_azure_stage
	FILE_FORMAT=(FORMAT_NAME = 'my_csv_format')
	MATCH_BY_COLUMN_NAME = CASE_INSENSITIVE;
+----------------------------------------------------------------------------------------------+--------+-------------+-------------+-------------+-------------+-------------+------------------+-----------------------+-------------------------+
| file                                                                                         | status | rows_parsed | rows_loaded | error_limit | errors_seen | first_error | first_error_line | first_error_character | first_error_column_name |
|----------------------------------------------------------------------------------------------+--------+-------------+-------------+-------------+-------------+-------------+------------------+-----------------------+-------------------------|
| azure://<ストレージアカウント>.blob.core.windows.net/<コンテナー名>/sample_data_20240412.csv    | LOADED |          10 |          10 |           1 |           0 | NULL        |             NULL |                  NULL | NULL                    |
+----------------------------------------------------------------------------------------------+--------+-------------+-------------+-------------+-------------+-------------+------------------+-----------------------+-------------------------+

>SELECT * FROM MYTABLE;
+----+--------------+----------+-----------+
| ID |          Val | Category | Date      |
|----+--------------+----------+-----------|
|  1 |  1.114388475 | A        | 2024/4/12 |
|  2 | -0.617730236 | B        | 2024/4/12 |
|  3 | -1.226039849 | A        | 2024/4/12 |
|  4 | -1.249994022 | A        | 2024/4/12 |
|  5 |  0.775035178 | A        | 2024/4/12 |
|  6 |  0.442294860 | C        | 2024/4/12 |
|  7 |  0.819239543 | A        | 2024/4/12 |
|  8 | -0.921003054 | B        | 2024/4/12 |
|  9 | -0.288820276 | B        | 2024/4/12 |
| 10 |  0.752006217 | B        | 2024/4/12 |
+----+--------------+----------+-----------+

		

問題なくデータをロードできました。

さいごに

Snowflake で Azure の Blob Storage を外部ステージに設定し、COPY コマンドによるデータロードを試してみました。
ストレージ統合周りの Azure での設定が必要な箇所は、他のクラウドサービスと設定内容が異なりますが、外部ステージ作成以降は同じ手順でロードできます。
こちらの内容が何かの参考になれば幸いです。

この記事をシェアする

FacebookHatena blogX

関連記事

Azure Blob Storage を外部ステージに設定し COPY コマンドによるデータロードを試してみる #SnowflakeDB | DevelopersIO