bigquery-api について
curl で BigQuery の REST API を利用し、SDK を使わずに SQL の実行やデータの確認を行うスキルです。クエリ用スクリプトに加え、ジョブ、データセット、テーブル、スキーマ、結果のページング方法を扱います。
主な機能
- 01SQL クエリの実行
- 02ジョブの送信と監視
- 03データセットとテーブルの一覧表示
- 04スキーマの確認と行のプレビュー
- 05クエリ結果のページング
活用シーン
- 01SQL で 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)を使うと、SDK を使わず、通常の curl だけで SQL の実行、ジョブの確認、データセットとテーブルスキーマの閲覧ができます。
中心となる概念はジョブです。すべてのクエリはプロジェクト内のジョブとして実行されます(料金はそのプロジェクトに請求されますが、データが保存されている場所とは限りません)。内部では、クエリは次のいずれかの方法で実行されます。scripts/bq_query.sh(操作 1)がこの処理を代行します。
- 同期(
jobs.query) — POST を 1 回実行し、タイムアウトまで待機します。クエリが制限時間内に終了した場合は、結果の行がインラインで返されます。 - 非同期(
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 は 1 つの引数(バッククォートで囲まれたテーブル名がシェルで壊れないよう、シングルクォートで囲んでください)または標準入力で渡します。インスタンス固有の設定には上記の
GCP_PROJECT/BQ_TOKENを使用します。--projectを指定すると、課金プロジェクトを上書きします。 --param NAME=TYPE:VALUE(複数回指定可能)を使うと、名前付きクエリパラメーターを送信できます。SQL 文字列への値の埋め込みより、こちらを優先してください。--dry-runはクエリを実行せず、スキャンされるバイト数を表示します。--max-gb Nを指定すると、N GiB を超えてスキャンするクエリは失敗します。--max-rows Nは取得する行数の上限を設定します(デフォルトは 10000、0はすべての行)。--jsonを指定すると、ヘッダー付き TSV の代わりに、1 行につき 1 つの JSON オブジェクトを出力します。ジョブ 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")
.status.state が DONE になるまで、GET ${BQ}/jobs/${JOB_ID}?location=${LOCATION} をポーリングします。呼び出しの間に待機し、ループに上限を設けてください(参考実装は scripts/bq_query.sh です)。完全な configuration.query 本文(宛先テーブル、書き込み処理、maximumBytesBilled、優先度、パラメーター)については、references/api.md の「Query job configuration」セクションを参照してください。
JOB_IDが空で返ってきた場合は、挿入自体が失敗しています。ポーリングせずに.errorを提示してください。- ポーリング時は必ず
locationを渡してください。ジョブは実行されたロケーションに固定されており、省略すると米国以外のデータセットでは 404 になることがあります。 DONEのジョブでも失敗している場合があります。結果を取得する前に.status.errorResultを確認してください。- クエリジョブの行を取得するには、
GET ${BQ}/queries/${JOB_ID}?location=${LOCATION}&maxResults=1000を呼び出します。セルはスキーマ順に{"f": [{"v": "..."}]}として返されます(列名は.schema.fields[].nameにあります)。後続のページは.pageTokenで取得します(「ページネーション」を参照)。
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}]}'
ネストされた列は、独自の fields[] を持つ type: "RECORD" として表示されます。ツリー全体が必要な場合は再帰的にたどってください。
8. クエリを使わずにテーブルの行をプレビューする(tabledata.list)
ストレージから行を直接読み取ります。クエリジョブは不要で、スキャンしたバイト数に応じた費用も発生しません。
bq_curl "${BQ}/datasets/${DATASET}/tables/${TABLE}/data?maxResults=10" \
| jq '.rows[]?.f | map(.v)'
ページネーション
リスト形式のすべてのエンドポイントで同じ方式が使われます。さらにデータがある場合、レスポンスにトークンが含まれるため、次の呼び出しで ?pageToken= として渡します。フィールドがなくなったら終了です。maxResults は 1 ページあたりの上限を指定します。実際の API の上限は固定の行数ではなくサイズで決まり(tabledata.list は 1 ページあたり約 10 MB、getQueryResults は約 20 MB)、同梱スクリプトでは 1 ページあたり 1000 行をデフォルトとしています。
レスポンスのフィールド名は統一されていません。エンドポイントが返すフィールドを確認してください。
pageToken—jobs.query、jobs.getQueryResults、tabledata.list。nextPageToken—datasets.list、tables.list、jobs.list、routines.list、models.list。
datasets.list のレスポンスで .pageToken を読み取ると、エラーなしに null が返され、1 ページしか取得できません。
クエリ結果には、もう 1 つ注意点があります。jobs.query と jobs.getQueryResults は totalRows も返します。これは 1 ページの行数が少なくても全体の件数を示します。進捗バーのサイズ設定には使えますが、終了条件としては使わないでください。
レート制限とクォータ
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 には、より詳しいエンドポイント一覧があります。ジョブ設定オブジェクトの詳細(宛先テーブル、書き込み方法、ロード/抽出/コピーの各ジョブ)、データセットとテーブルの作成・更新、ルーティン、行レベルのアクセス ポリシーが記載されています。上記で扱っていないエンドポイントや、書き込み時の正確なリクエストボディの形式が必要な場合は、こちらを参照してください。