mcpField
S
snowflake-api

snowflake-api

github.com/anthropics数据与数据库7442 次安装3 周前更新
代码仓库

关于 snowflake-api

snowflake-api 是通过 Snowflake SQL API v2 提交 SQL 并处理结果的技能,介绍如何使用附带脚本或直接调用 API 执行查询、查看目录、获取分区结果和管理语句。

主要功能

  1. 01使用附带脚本运行 SQL
  2. 02轮询异步语句
  3. 03获取分区查询结果
  4. 04用 SHOW 和 DESCRIBE 浏览目录
  5. 05提交多条语句
  6. 06取消语句并进行幂等重试

适用场景

  1. 01在 Snowflake 中运行 SQL 查询
  2. 02查看数据库、架构、表和列
  3. 03从语句句柄恢复查询结果
  4. 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 字符串后,会返回一个语句句柄,以及查询结果(适用于快速查询)或 202 Accepted 响应,供你轮询。大型结果会拆分为多个分区,需要逐个获取。没有单独的“列出表”端点——浏览目录只需执行 SQL(SHOW TABLES、 INFORMATION_SCHEMA)。

请求设置

身份验证由运行时处理——凭据会注入发送到此 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 会拒绝没有该标头的请求。--compressed 对结果分区很重要,因为返回内容带有 Content-Encoding: gzip。)

健全性检查——确认账户标识符正确,并且工作区已连通:

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 可以作为一个带引号的参数传入,也可以通过 stdin 传入。实例的具体配置来自上文的 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 s)是服务器端执行时限——超出时限的语句会被取消;--max-wait(默认 600 s)是脚本轮询并等待的最长时间,超时后脚本会放弃等待。
  • --max-rows N 限制获取的行数(默认 10000,0 = 全部);--json 会为每行输出一个 JSON 对象,而不是带表头的 TSV。句柄、行数和错误会输出到 stderr。
  • 单元格按 API 的原始字符串编码输出(因此日期是 epoch 天数,时间戳是 epoch 秒——请参阅“错误处理”中的注意事项)。
  • 退出代码: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 = 仍在运行(稍等后再次轮询),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。使用 ?partition=N 获取其余分区,其中 N 从 1 到 partitionInfo|length - 1。分区是稳定的(可并行或乱序获取),除第一个分区外均采用 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. 在一个请求中运行多条语句

用 ; 分隔,并将 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,它们会作为普通语句运行。失败时(对象不存在、无权限)会返回 422,包含 {code, message, sqlState},且不含 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} 条目组成的数组;遍历索引,无需 next-token。每个分区的大小都有限制,以控制响应体积(大约几千行或未压缩约 10 MB)。

速率限制

Snowflake 没有公布 SQL API 固定的每秒请求数上限。你实际遇到的限制包括:

  • 每个仓库的并发语句数(MAX_CONCURRENCY_LEVEL,默认值为 8)——超出的查询会在 Snowflake 内部排队,而不是在 HTTP 层排队,因此不会收到 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",每个 ? 对应一个)。
  • 401 — 缺少凭据或凭据被拒绝。检查 SNOWFLAKE_ACCOUNT 是否指向正确的账户,以及是否提供了令牌和类型标头。如果问题持续存在,说明此工作区未配置凭据——请报告此问题。
  • 404 — 未找到句柄。结果保留 24 h;超过此时间后,句柄将失效。也可能是句柄错误。
  • 408 — 语句超出请求的 timeout,因此已取消。请提高(或省略)timeout 后重新提交。
  • 422 — 语句执行失败(SQL 错误、已取消)。message 和 sqlState 包含 SQL 错误信息。不要盲目重试。
  • 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 s 的最低计费时长(按每次仓库启动计费,而非每个查询)——请尽可能将小型查询批量处理。

深入了解

references/api.md 提供了更完整的参考资料——包括完整的请求正文字段、resultSetMetaData 结构、所有 parameters 会话选项、多语句和子句柄机制、监控端点(/api/v2/statements/{handle} 状态值),以及绑定类型和 VARIANT/ARRAY 处理的说明。如果你需要了解以上内容未涵盖事项的确切结构,请阅读该文档。

评论

支持 Markdown