关于 bigquery-api
通过 curl 使用 BigQuery REST API 执行 SQL 和查看数据的技能,无需 SDK。它提供查询脚本,并介绍作业、数据集、表、架构及结果分页。
主要功能
- 01执行 SQL 查询
- 02提交并监控作业
- 03列出数据集和表
- 04查看架构并预览行
- 05对查询结果分页
适用场景
- 01使用 SQL 查询 BigQuery 数据
- 02检查表架构并查看样例行
- 03监控或取消查询作业
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ anthropics/ claude-tag-plugins --skill bigquery-api安装后在 Claude Code 中输入/bigquery-api确认已加载。
附带文件references/api.mdscripts/bq_query.sh
详细介绍
BigQuery 的 REST API(bigquery.googleapis.com/bigquery/v2)让你可以直接使用普通的 curl 运行 SQL、检查作业,以及浏览数据集和表架构,无需 SDK。
核心概念是作业。每个查询都会作为作业在一个项目中运行(费用计入该项目,但数据不一定存储在其中)。在底层,查询会以两种方式之一运行——scripts/bq_query.sh(操作 1)会为你处理这些流程:
- 同步(
jobs.query)——发送一个 POST 请求,最多阻塞至超时;如果查询及时完成,则直接返回行数据。 - 异步(
jobs.insert→jobs.get→jobs.getQueryResults)——提交作业、轮询,然后分页获取结果。直接使用此方式来指定目标表、BATCH优先级,或执行加载/提取/复制作业。
其余操作(数据集、表、架构)都是简单的 GET 请求。
请求设置
认证由运行时处理——凭据会注入发送到此 API 的请求中,因此无需进行任何设置。请勿尝试创建、生成、刷新或验证令牌或密钥。凭据变量仅用于确保请求格式正确;如果某个变量未设置,请将其设为任意占位值。持续出现 401/403 错误意味着此工作区未配置凭据——请报告此问题,而不是排查认证故障。
每个请求都带有 Authorization: Bearer ...,并以计费项目为根:
export GCP_PROJECT="my-project" # the project that pays for queries — must be real
export BQ_TOKEN="placeholder" # injected by the runtime; any value works
定义一个辅助函数,避免在每次调用时重复填写基础 URL 和认证标头:
export BQ="https://bigquery.googleapis.com/bigquery/v2/projects/${GCP_PROJECT}"
bq_curl() { curl -sS "$@" -H "Authorization: Bearer ${BQ_TOKEN}"; }
完整性检查——确认项目正确,并确认工作区已完成配置:
bq_curl "${BQ}/datasets?maxResults=1" | jq .
# 200 with a "datasets" array on success (the key is omitted entirely when the project
# has no datasets — that's still a success); 401/403 otherwise.
核心操作
1. 运行查询(scripts/bq_query.sh)
通过捆绑的脚本运行 SQL(路径相对于此技能目录):脚本会提交
查询,持续轮询直至完成,并在整个过程中传递 location;随后分页获取所有结果页,
并解码标量列的 f/v 单元格编码(嵌套/重复列会以原始
f/v JSON 形式输出——如果需要将其扁平化,请使用 jq 后处理)。
scripts/bq_query.sh \
'SELECT name, SUM(number) AS total
FROM `bigquery-public-data.usa_names.usa_1910_current`
WHERE state = @state GROUP BY name ORDER BY total DESC LIMIT 10' \
--param state=STRING:CA --max-gb 5
- SQL 作为一个参数传入(用单引号括起来,以免 shell 处理反引号括起的表名),也可以通过标准输入传入。
实例的具体配置来自上述
GCP_PROJECT/BQ_TOKEN;--project可覆盖计费项目。 --param NAME=TYPE:VALUE(可重复使用)可发送具名查询参数——建议使用此方式,而不是 将值直接插入 SQL 字符串。--dry-run会显示查询运行时将扫描的字节数,但不会实际运行查询;--max-gb N会使查询 在扫描量超过 N GiB 时失败。--max-rows N会限制获取的行数(默认值为 10000,0= 全部);--json会为每一行输出一个 JSON 对象,而不是带表头的 TSV。作业 ID、扫描字节数和行数会输出到 stderr。- 退出码:
0表示成功;1表示请求或查询失败(API 错误信息输出到 stderr);2表示在等待--max-wait秒(默认值为 600)后放弃等待——作业 ID 会输出到 stderr;请使用下面的端点轮询作业。
如果脚本出错,请阅读脚本——它只是普通的 curl + jq——并参考 references/api.md 进行排查。
对于数组/结构体参数、目标表或写入处置方式、BATCH 优先级,或
非查询作业(加载/提取/复制),请直接使用 jobs.insert(下一个操作)。
2. 直接提交作业(jobs.insert → jobs.get)
当你需要指定目标表、写入处置方式、BATCH 优先级,或需要提交非查询作业(加载/提取/复制)时,请自行提交作业并轮询。POST ${BQ}/jobs 会立即返回一个 jobReference:
JOB=$(bq_curl -X POST "${BQ}/jobs" -H "Content-Type: application/json" \
-d '{"configuration": {"query": {"query": "SELECT ...", "useLegacySql": false}}}')
JOB_ID=$(jq -r '.jobReference.jobId // empty' <<<"$JOB")
LOCATION=$(jq -r '.jobReference.location // empty' <<<"$JOB")
然后轮询 GET ${BQ}/jobs/${JOB_ID}?location=${LOCATION},直到 .status.state 为 DONE——两次调用之间稍作等待,并限制循环次数(scripts/bq_query.sh 是参考实现)。完整的 configuration.query 请求体——目标表、写入处置方式、maximumBytesBilled、优先级、参数——见 references/api.md 的 Query job configuration 一节。
- 如果返回的
JOB_ID为空,说明插入操作本身失败;请显示.error,不要轮询。 - 轮询时始终传入
location——作业会固定在其运行所在的位置,省略它可能会导致非 US 数据集返回 404。 DONE状态的作业仍可能失败:获取结果前请检查.status.errorResult。- 使用
GET ${BQ}/queries/${JOB_ID}?location=${LOCATION}&maxResults=1000获取查询作业的行——单元格按架构顺序以{"f": [{"v": "..."}]}的形式返回(列名位于.schema.fields[].name);后续页面由.pageToken指示(参见 Pagination)。
3. 取消正在运行的作业
bq_curl -X POST "${BQ}/jobs/${JOB_ID}/cancel?location=${LOCATION}" | jq '.job.status // .error'
取消操作尽力而为;请轮询 jobs.get 确认。
4. 列出最近的作业
bq_curl "${BQ}/jobs?maxResults=20&projection=full&allUsers=false&stateFilter=done" \
| jq '.jobs[]? | {id: .jobReference.jobId, state: .status.state, query: (.configuration.query.query // "" | .[0:80]), bytes: .statistics.query.totalBytesProcessed}'
5. 列出数据集
bq_curl "${BQ}/datasets?maxResults=100" \
| jq '.datasets[]? | {id: .datasetReference.datasetId, location}'
传入 ?all=true 以包含隐藏数据集。若要列出其他项目的数据集,请替换 URL 中的项目(你需要在那里拥有 bigquery.datasets.get 权限)。
6. 列出数据集中的表
DATASET="my_dataset"
bq_curl "${BQ}/datasets/${DATASET}/tables?maxResults=100" \
| jq '.tables[]? | {id: .tableReference.tableId, type, creationTime}'
type 可以是 TABLE、VIEW、EXTERNAL、MATERIALIZED_VIEW 或 SNAPSHOT。
7. 获取表的架构和大小
TABLE="events"
bq_curl "${BQ}/datasets/${DATASET}/tables/${TABLE}" \
| jq '{rows: .numRows, bytes: .numBytes, partitioning: .timePartitioning, schema: [.schema.fields[]? | {name, type, mode}]}'
嵌套列会以 type: "RECORD" 的形式出现,并带有自己的 fields[]——如需完整结构,请递归处理。
8. 不执行查询即可预览表行(tabledata.list)
直接从存储中读取行——无需查询作业,也不会产生扫描字节费用。
bq_curl "${BQ}/datasets/${DATASET}/tables/${TABLE}/data?maxResults=10" \
| jq '.rows[]?.f | map(.v)'
分页
所有列表类端点都采用相同的方式:有更多内容时,响应会携带一个令牌;在下一次调用时将其作为 ?pageToken= 传回。当该字段不存在时停止。maxResults 限制单页结果数;实际的 API 上限取决于大小(每个 tabledata.list 页面约 10 MB,每个 getQueryResults 页面约 20 MB),而非固定行数——随附脚本默认每页 1000 行。
响应字段名称并不统一——请确认端点返回的是哪个字段:
pageToken—jobs.query、jobs.getQueryResults、tabledata.list。nextPageToken—datasets.list、tables.list、jobs.list、routines.list、models.list。
读取 datasets.list 响应中的 .pageToken 会静默返回 null,导致你只能获取一页。
查询结果还有一点需要注意:jobs.query 和 jobs.getQueryResults 还会返回 totalRows,即使单页结果更少,它也表示完整的行数——请用它设置进度条的规模,而不要将其用作停止条件。
速率限制与配额
BigQuery 限制的是项目配额,而非单个请求的速率。你可能遇到的限制如下:
- 并发查询:BigQuery 决定同时运行的查询数量(动态并发),其余查询会排队——每个项目、每个区域最多可排队 1,000 个交互式查询。超过此数量后,提交会因
quotaExceeded/jobRateLimitExceeded而失败。 - API 请求:大多数方法对每位用户的每种方法限制为每秒约 100 个请求(
jobs.get和tabledata.list允许更高频率)——轮询时请使用sleep,不要紧密循环。 - 按需扫描字节数和槽位时间配额取决于你的计费模式。
429 和 403 rateLimitExceeded / quotaExceeded 响应会在 error.errors[].reason 中包含可重试原因。请采用指数退避后重试;不要缩短轮询间隔。
错误处理
每个错误响应的格式都是 {"error": {"code": N, "message": "...", "errors": [{"reason": "..."}]}} ——在进行投影前检查 .error。reason 字符串是最有用的字段。
401— 凭据缺失或被拒绝。检查是否设置了BQ_TOKEN(任意值均可)。如果问题仍然存在,说明此工作区尚未配置凭据——请报告此问题。403 accessDenied— 调用方没有项目或数据集的权限。检查 URL 中的项目(计费项目)与拥有数据的项目是否一致——它们可能不同。为数据授予roles/bigquery.dataViewer,为计费项目授予roles/bigquery.jobUser。404 notFound— 作业、数据集或表不存在,或者查询作业时遗漏了location。仔细核对完整引用(project.dataset.table)。调用jobs.get/getQueryResults时始终传入?location=。400 invalidQuery— SQL 错误。message中包含行号和列号。请记住设置useLegacySql: false。- 作业的
status.errorResult— 查询已运行但失败。作业状态可以是DONE,但仍然失败——获取结果前始终检查status.errorResult。 5xx/backendError— Google 端的暂时性错误。请采用退避策略重试。读取作业可安全重试;对于写入作业,请在重试前检查首次尝试是否已实际运行。
深入了解
references/api.md 中有更完整的端点目录——详细介绍作业配置对象(目标表、写入处置方式、加载/导出/复制作业)、数据集和表的创建/更新、例程以及行级访问策略。需要使用上文未涵盖的端点,或确认写入请求体的确切格式时,请阅读该文件。