snowflake-api について
snowflake-apiは、Snowflake SQL API v2でSQLを送信し、結果を処理するスキルです。付属スクリプトまたはAPI呼び出しによるクエリ実行、カタログ確認、分割結果の取得、ステートメント管理を案内します。
主な機能
- 01付属スクリプトでSQLを実行
- 02非同期ステートメントをポーリング
- 03分割されたクエリ結果を取得
- 04SHOWとDESCRIBEでカタログを確認
- 05複数ステートメントを送信
- 06ステートメントのキャンセルと冪等な再試行
活用シーン
- 01SnowflakeでSQLクエリを実行
- 02データベース、スキーマ、テーブル、列を確認
- 03ステートメントハンドルから結果を復旧
- 04再試行可能または複数のステートメントを送信
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ anthropics/ claude-tag-plugins --skill snowflake-apiインストール後、Claude Code で/snowflake-apiを入力して読み込まれたか確認します。
同梱ファイルreferences/api.mdscripts/snow_query.sh
詳細
Snowflake の SQL API v2(/api/v2/statements)は、SQL の実行と結果の取得を行うための薄い REST レイヤーです。
SQL 文字列を POST すると、ステートメントハンドルと、高速なクエリの場合は結果が返され、そうでない場合はポーリング用の
202 Accepted が返されます。大きな結果はパーティションに分割され、1 つずつ取得します。
個別の「テーブル一覧」エンドポイントはありません。カタログの参照も、SHOW TABLES や
INFORMATION_SCHEMA を使った SQL で行います。
リクエストの設定
認証はランタイムが処理します。この API への送信リクエストには認証情報が挿入されるため、
設定は不要です。トークンやキーを作成、発行、更新、検証しようとしないでください。
認証情報の変数はリクエストの形式を整えるためだけに存在します。未設定の場合は、任意の
プレースホルダー値を設定してください。401 が継続する場合は、このワークスペースに認証情報が設定されていません。
認証のデバッグではなく、その旨を報告してください。
アカウント識別子は実際の値である必要があります。これはホスト名です。Snowflake の URL で
.snowflakecomputing.com より前の部分です。例:xy12345.us-east-1、または組織形式の myorg-myaccount。
export SNOWFLAKE_ACCOUNT="xy12345.us-east-1" # your account identifier — must be real
export SNOWFLAKE_BASE="https://${SNOWFLAKE_ACCOUNT}.snowflakecomputing.com"
export SNOWFLAKE_TOKEN="placeholder" # injected by the runtime; any value works
export SNOWFLAKE_TOKEN_TYPE="${SNOWFLAKE_TOKEN_TYPE:-OAUTH}" # leave as provided by the runtime
ヘルパーと動作確認
すべてのリクエストで同じヘッダーを使用します。ヘルパーを一度定義します。
snowapi() {
curl -sS --compressed "$@" \
-H "Authorization: Bearer ${SNOWFLAKE_TOKEN}" \
-H "X-Snowflake-Authorization-Token-Type: ${SNOWFLAKE_TOKEN_TYPE}" \
-H "Content-Type: application/json" -H "Accept: application/json" \
-H "User-Agent: curl-sql-api/1.0"
}
(User-Agent は必須です。指定しないと Snowflake はリクエストを拒否します。結果パーティションは
Content-Encoding: gzip で返されるため、--compressed が重要です。)
動作確認 — アカウント識別子が正しく、ワークスペースが接続されていることを確認します。
snowapi -X POST "${SNOWFLAKE_BASE}/api/v2/statements" \
-d '{"statement":"SELECT CURRENT_USER(), CURRENT_ROLE(), CURRENT_WAREHOUSE()","timeout":10}' | jq .
# Returns the configured user/role/warehouse on success.
主な操作
1. ステートメントを実行する(scripts/snow_query.sh)
付属のスクリプトを使って SQL を実行します(パスはこのスキルのディレクトリからの相対パスです)。スクリプトは
ステートメントを送信し、完了するまでハンドルをポーリングして、すべての結果パーティションを処理し(gzip に対応)、
デコードした行を出力します。単一ステートメントのクエリ、SHOW、DESCRIBE に使用してください。
scripts/snow_query.sh --warehouse MY_WH --bind TEXT:1996-01-01 \
'SELECT o_orderdate, COUNT(*) n FROM snowflake_sample_data.tpch_sf1.orders
WHERE o_orderdate >= ? GROUP BY 1 ORDER BY 1 LIMIT 20'
- SQL は、引用符で囲んだ単一の引数として渡すか、標準入力から渡します。インスタンス固有の設定には、上記の
SNOWFLAKE_ACCOUNT/SNOWFLAKE_TOKEN/SNOWFLAKE_TOKEN_TYPEを使用します(SNOWFLAKE_BASE_URLを指定するとホストが上書きされます)。 --warehouse/--database/--schema/--roleはセッションコンテキストを設定します(省略した場合は、それぞれユーザーの Snowflake のデフォルト値が使われます)。--tagは監査用にQUERY_TAGを設定します。--bind TYPE:VALUE(複数指定可)は、位置指定の?プレースホルダーに順番に値をバインドします。値を SQL 文字列に直接埋め込むより、こちらを優先してください。型にはreferences/api.mdに記載されたバインド型を使用します。--timeout(デフォルトは 300 秒)はサーバー側の実行上限です。これを超えたステートメントはキャンセルされます。--max-wait(デフォルトは 600 秒)は、スクリプトが処理を断念するまでポーリングする時間です。--max-rows Nは取得する行数の上限を設定します(デフォルトは 10000、0= すべて)。--jsonを指定すると、ヘッダー付きの TSV の代わりに、1 行ごとに 1 つの JSON オブジェクトを出力します。ハンドル、行数、エラーは stderr に出力されます。- セルは API の生の文字列形式で出力されます(日付はエポック日数、タイムスタンプはエポック秒です。「エラー処理」の注意点を参照してください)。
- 終了コード:
0は成功、1はリクエストまたは SQL の失敗(Snowflake のcode/sqlState/messageを stderr に出力)、2は実行中のまま--max-waitを超えて処理を断念したことを示します。ハンドルは stderr に出力されます。以下のエンドポイントを使って取得またはキャンセルしてください。
スクリプトでエラーが発生した場合は、内容を確認してください。これは curl と jq だけで書かれているため、
references/api.md を参照してデバッグできます。
複数ステートメントのリクエスト、冪等な requestId の再試行、配列バインド、キャンセル、または
すでに取得済みのハンドルからの結果取得には、以下のエンドポイントを直接使用してください。
2. 既存のハンドルから結果を取得する
GET /api/v2/statements/{handle} — スクリプトが終了コード 2 のタイムアウトになった後の復旧方法、または別の方法で取得したハンドルに使用します。202 = 実行中(sleep を挟んで再度ポーリングします)、200 = 完了し、パーティション 0 の結果がインラインで返されます、422 = ステートメントが失敗しました。
snowapi "${SNOWFLAKE_BASE}/api/v2/statements/${HANDLE}" -o /tmp/sf.json -w '%{http_code}\n'
jq '{cols: [.resultSetMetaData.rowType[]?.name], parts: .resultSetMetaData.partitionInfo, rows: .data[:5]}' /tmp/sf.json
- 列は
resultSetMetaData.rowType[]に、行は文字列の配列としてdata[]に含まれます(エンコード表についてはreferences/api.mdの「Result metadata & partitions」セクションを参照してください)。 resultSetMetaData.partitionInfo[]には、各パーティションとそのrowCountが含まれます。残りの結果は、partitionInfo|length - 1までの 1 から N について?partition=Nを指定して取得します。パーティションは安定しているため(並列または順不同で取得できます)、最初のパーティション以降は gzip 圧縮されます(ヘルパーの--compressedが処理します)。また、dataのみを含み、メタデータはありません。- 結果はステートメントの完了後 24 時間 保持されます。それを過ぎると、ハンドルは
404を返します。
3. 実行中のステートメントをキャンセルする
snowapi -X POST "${SNOWFLAKE_BASE}/api/v2/statements/${HANDLE}/cancel" | jq .
キャンセルはベストエフォートです。ステートメントがすでに完了している場合、何も行われません。
4. requestId を使った冪等な送信
POST が再試行される可能性がある場合(不安定なネットワーク、タイムアウト)は、クライアントが生成した UUID を requestId として渡します。同じ requestId で retry=true を指定して再試行すると、再実行されず、元のステートメントのハンドルが返されます。
RID=$(uuidgen)
snowapi -X POST "${SNOWFLAKE_BASE}/api/v2/statements?requestId=${RID}" -d '{"statement":"INSERT INTO t VALUES (1)","warehouse":"MY_WH"}'
# On timeout, retry:
snowapi -X POST "${SNOWFLAKE_BASE}/api/v2/statements?requestId=${RID}&retry=true" -d '{"statement":"INSERT INTO t VALUES (1)","warehouse":"MY_WH"}'
5. 1 つのリクエストで複数のステートメントを実行する
ステートメントを ; で区切り、MULTI_STATEMENT_COUNT に正確な件数(または「任意の件数」を表す 0)を設定します。親ハンドルと、子ごとのハンドルが返されます。
snowapi -X POST "${SNOWFLAKE_BASE}/api/v2/statements" -d '{
"statement": "CREATE TEMP TABLE tmp AS SELECT 1 AS x; SELECT * FROM tmp;",
"warehouse": "MY_WH",
"parameters": {"MULTI_STATEMENT_COUNT": "2"}
}' | jq '{parent: .statementHandle, children: .statementHandles, msg: .message}'
各子の結果は、それぞれのハンドルで取得します。BEGIN/COMMIT/ROLLBACK、USE、ALTER SESSION、および一時テーブル/ステージの作成は、複数ステートメントのリクエスト内でのみサポートされます。単一のステートメントとして実行すると、422 で失敗します。複数ステートメントのリクエストではバインディングはサポートされません。
6. カタログを参照する(データベース、スキーマ、テーブル、列)
REST のカタログエンドポイントはありません。通常のステートメントとして実行される SHOW/DESCRIBE を使用します。失敗(オブジェクトが存在しない、権限がない)の場合は、{code, message, sqlState} とともに 422 が返され、data キーはありません。最初に一度エラーを処理すれば、その後の呼び出しでは .data があるものとして扱えます。
snowapi -X POST "${SNOWFLAKE_BASE}/api/v2/statements" -d '{"statement":"SHOW DATABASES","timeout":20}' \
| jq -r 'if .data then (.data[] | @tsv) else "error \(.code // "?"): \(.message // .)" end'
statement を次のいずれかに置き換えます。SHOW SCHEMAS IN DATABASE MY_DB、SHOW TABLES IN SCHEMA MY_DB.PUBLIC、DESCRIBE TABLE MY_DB.PUBLIC.EVENTS、SHOW WAREHOUSES LIKE 'MY_WH'(列 2 = 状態:STARTED/SUSPENDED/RESUMING/SUSPENDING)。
バージョン間で列セットを予測可能にするには、代わりに INFORMATION_SCHEMA をクエリします。例:SELECT table_name, row_count, bytes FROM my_db.information_schema.tables WHERE table_schema='PUBLIC'、または SELECT column_name, data_type, is_nullable FROM my_db.information_schema.columns WHERE table_schema='PUBLIC' AND table_name='EVENTS' ORDER BY ordinal_position。
列名で行の値を対応付けるには、resultSetMetaData.rowType[].name と各 data[] 行を組み合わせます。
jq '[.resultSetMetaData.rowType[]?.name] as $c | .data[] | [$c,.] | transpose | map({key:.[0],value:.[1]}) | from_entries。
ページネーション
ページネーションはカーソルではなく、パーティション 単位です。resultSetMetaData.partitionInfo は {"rowCount", "uncompressedSize"} エントリーの配列です。次のトークンはなく、インデックスをループします。各パーティションのサイズは、レスポンスが扱いやすくなるように制限されています(おおよそ数千行、または非圧縮で約 10 MB)。
レート制限
Snowflake は SQL API の固定リクエスト数/秒の上限を公開していません。実際に遭遇する制限は次のとおりです。
- ウェアハウスあたりの同時ステートメント数(
MAX_CONCURRENCY_LEVEL、デフォルトは 8)— 超過したクエリは HTTP 層ではなく Snowflake 内部でキューに入るため、429は返されません。代わりにQUEUED状態のままになります。 429 Too Many Requestsは、ポーリングエンドポイントに過剰なリクエストを送ると発生します。間隔を空け、Retry-Afterがあればその値を守ってください。- 認証情報の有効期間 — ランタイムが認証情報を提供し、更新します。
401が継続する場合は、設定済みの認証情報に問題があるため、再認証を試みるのではなく報告してください。
ポーリングは高頻度のループではなく、sleep を使ってください。また、ポーリングなしでほとんどのクエリがインラインで返るように、POST の timeout は十分に長く設定してください。
エラー処理
Snowflake は HTTP ステータスと、code、sqlState、message、statementHandle を含む JSON 本文を返します。code は Snowflake 固有の数値文字列です(例:"390302")。
200— 完了しており、結果はインラインで返されます。data[]を読み取ってください。ページがさらにあるかどうかはresultSetMetaData.partitionInfoで確認してください。202— 実行中(または非同期で送信済み)です。GET .../statements/{handle}をポーリングしてください。本文にはstatementStatusUrlとmessageが含まれます。400— リクエストの形式が不正です。messageを確認してください。よくある原因:Content-Typeがない、JSON が不正、バインドインデックスが間違っている(バインドは 1 から始まる文字列です:"1"、"2"。それぞれの?に 1 つずつ対応します)。401— 認証情報がないか、拒否されました。SNOWFLAKE_ACCOUNTが正しいアカウントを指していること、およびトークン/タイプのヘッダーが設定されていることを確認してください。解消しない場合、認証情報がこのワークスペース用に設定されていないため、報告してください。404— ハンドルが見つかりません。結果は 24 時間保持され、それを過ぎるとハンドルは無効になります。ハンドルが間違っている場合もあります。408— ステートメントがリクエストのtimeoutを超過し、キャンセルされました。timeoutを延長する(または省略する)か、再送信してください。422— ステートメントに失敗しました(SQL エラー、キャンセル)。SQL エラーの詳細はmessageとsqlStateに含まれます。むやみに再試行しないでください。429— レート制限に達しました。Retry-Afterに従って間隔を空けてください。503/504— 一時的なエラーです。間隔を空けて再試行してください。POST を再試行する場合は、冪等性を保つため、同じrequestIdとretry=trueを指定してください。
注意すべき点:
- デフォルトではすべて大文字になります。 引用符で囲まれていない識別子は大文字に変換されて解決されます。
SHOW TABLES IN schema my_db.publicとMY_DB.PUBLICは同じですが、"my_db"."public"は異なります。 - SQL のバインドプレースホルダーは
?で、バインドは配列ではなく、キーが文字列で 1 から始まるオブジェクトです:{"1": {...}, "2": {...}}。typeにかかわらず、値は常に文字列です。型の一覧と配列バインド形式については、references/api.md(Bindings)を参照してください。 data[]の値はすべて文字列であり、日付/タイムスタンプは ISO 形式ではありません —dateはエポックからの日数("18262")、timestamp_*は小数点以下 9 桁のエポック秒です。resultSetMetaData.rowType[].typeに基づいて解析してください。型ごとの完全なエンコード表はreferences/api.md(Result metadata & partitions)にあります。- データをスキャンする処理にはウェアハウスが必要です。 メタデータのみを扱うステートメント(多くの
SHOWコマンド、DESCRIBE)には不要ですが、SELECTには必要です。ウェアハウスが指定されていない場合は、明確なエラーメッセージが返されます。停止中のウェアハウスに対するクエリは自動的に再開されます(起動に時間がかかります)。再開のたびに 60 秒分の最低料金が発生します(クエリごとではなく、ウェアハウスの起動ごとです)。可能であれば、小規模な検索をまとめて実行してください。
詳細情報
references/api.md には、より詳しいリファレンスが記載されています。リクエスト本文の全フィールド、resultSetMetaData の形式、parameters のすべてのセッションオプション、複数ステートメントと子ハンドルの仕組み、監視エンドポイント(/api/v2/statements/{handle} のステータス値)、バインド型と VARIANT/ARRAY の扱いに関する注意事項が含まれます。上記で説明されていない内容の正確な形式が必要な場合は、参照してください。