bigquery について
BigQueryを扱う開発者やエージェント向けのCLI・MCPガイドです。クエリやデータセット、テーブルの管理に加え、自動ドライランと費用確認でクエリコストを把握できます。
主な機能
- 01CLIでクエリ、データセット、テーブル、ジョブを管理
- 02クエリを自動ドライランして費用を確認
- 03JSON、テキスト、JSONL形式に対応
- 04読み取り専用MCPツールと任意の書き込みツール
- 05テーブルのスキーマとメタデータをリソースとして公開
活用シーン
- 01スキャン量を確認してSQLを実行
- 02CLIまたはMCPでデータセットやテーブルを探索
- 03BigQueryへデータを挿入または一括ロード
MCP 対応
BigQuery MCPサーバーは、クエリ、費用見積もり、データセットやテーブルの検出、テーブル記述のツールを提供し、スキーマとメタデータもリソースとして公開します。既定は読み取り専用で、`--enable-writes` により書き込みツールを有効化できます。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ lanej/ dotfiles --skill bigqueryインストール後、Claude Code で/bigqueryを入力して読み込まれたか確認します。
詳細
BigQuery CLI と MCP サーバー
CLI と MCP の比較
CLI は完全なインターフェースです。MCP ツールはその一部です。
以下の MCP ツールのセクションに記載されていない操作には、デフォルトで bigquery CLI を使用してください。エージェントが構造化されたツール呼び出しのセマンティクスを必要とする場合は、MCP を使用してください。
認証
Google Cloud SDK(gcloud)の ADC を使用します。BigQuery 専用の認証は不要です。
bigquery auth check # verify status and scopes
出力形式のデフォルト
| コマンド | デフォルト | 備考 |
|---|---|---|
query | JSON | メタデータ(bytes、cost、cacheHit)を含みます |
datasets list | テキスト | 人が読みやすい形式です |
tables list | テキスト | 人が読みやすい形式です |
すべてのコマンドで --format json|text|jsonl を指定できます。
クエリ操作
# Basic (automatic dry-run + cost confirmation)
bigquery query "SELECT * FROM dataset.table LIMIT 10"
# Skip cost confirmation (required for automation)
bigquery query --yes "SELECT COUNT(*) FROM dataset.table"
# JSONL output (one object per line — for pipelines/DuckDB)
bigquery query --jsonl "SELECT * FROM dataset.table"
# Stream large results
bigquery query "SELECT * FROM large_table" --stream > results.jsonl
# From file / stdin
bigquery query --file query.sql
cat query.sql | bigquery query --stdin --yes
# Dry run (cost estimate, $0 to run)
bigquery dry-run "SELECT * FROM large_table WHERE date >= '2025-01-01'"
コストへの配慮:各クエリの前に自動でドライランを実行し、コストがしきい値(デフォルト:1 GB)を超える場合は確認を求めます。応答には bytesProcessed、estimatedCostUSD、cacheHit が含まれます。
主なフラグ:--yes、--format、--jsonl、--stream、--cost-threshold、--max-results、--project
重要:--max-results が制限するのは返される行数であり、スキャンされるバイト数ではありません(コストは削減されません)。代わりに SQL で LIMIT を使用してください。
データセット操作
bigquery datasets list [--project PROJECT]
bigquery datasets describe PROJECT.DATASET
bigquery datasets create PROJECT.DATASET [--description "..." --location US --default-ttl 30]
bigquery datasets update PROJECT.DATASET --description "..."
bigquery datasets delete PROJECT.DATASET [--force --yes]
テーブル操作
# Read
bigquery tables list PROJECT.DATASET [--max-results 20]
bigquery tables describe PROJECT.DATASET.TABLE
# Write
bigquery tables create TABLE --schema '[{"name":"id","type":"STRING"}]'
bigquery tables update TABLE --description "..."
# Insert (streaming, <1000 rows)
bigquery tables insert TABLE file.jsonl --format jsonl
cat data.jsonl | bigquery tables insert TABLE - --format jsonl
# Load (bulk, >10MB — from Cloud Storage)
bigquery tables load TABLE gs://bucket/data.csv --format csv --write-disposition WRITE_TRUNCATE
# Copy / extract / delete
bigquery tables copy SOURCE DEST [--write-disposition WRITE_TRUNCATE]
bigquery tables extract TABLE gs://bucket/output.csv --format csv
bigquery tables delete TABLE
tables load の注意点:--yes は受け付けません。また、--write-disposition には大文字を指定する必要があります(append ではなく WRITE_APPEND)。
ジョブ管理
bigquery jobs list [--state-filter running|done --all-users]
bigquery jobs get JOB_ID
bigquery jobs cancel JOB_ID
Python のサブプロセスパターン
# query via stdin
result = subprocess.run(
["bigquery", "query", "--format", "jsonl", "--yes", "--stdin"],
input=sql, capture_output=True, text=True, check=True
)
# bulk load (no --yes for tables load)
subprocess.run(
["bigquery", "tables", "load", "--format", "json",
"--write-disposition", "WRITE_APPEND", table, tmpfile],
check=True
)
MCP サーバー
起動
bigquery mcp stdio # read-only (default)
bigquery mcp stdio --enable-writes # with write tools
bigquery mcp http --port 3000 # HTTP mode
MCP ツール(デフォルトでは読み取り専用)
Claude Code では、完全な識別子は mcp__bigquery__* です。
読み取りツール(常に利用可能):
| ツール | 説明 |
|---|---|
query | 自動ドライランとコストガード付きで SQL を実行します |
dry_run | 実行せずにコストを見積もります($0) |
list_datasets | データセットを一覧表示します。bigquery://project.dataset URI を返します |
list_tables | テーブルを一覧表示します。bigquery://project.dataset.table URI を返します |
describe_table | 完全なスキーマ、行数、メタデータを返します |
書き込みツール(--enable-writes が必要):
| ツール | 説明 |
|---|---|
create_dataset | 新しいデータセットを作成します |
create_table | スキーマ、パーティショニング、クラスタリングを指定してテーブルを作成します |
insert_rows | ストリーミング挿入(1000 行未満) |
load_data | GCS URI から読み込みます(バルク) |
execute_ddl | DDL/DML(CREATE、INSERT、UPDATE など)を実行します |
MCP リソース
テーブルは bigquery://{project.dataset.table} を介してリソースとして公開されます。リソースを取得すると、ツール呼び出し枠を消費することなく、describe_table と同じ出力(スキーマ、行数、メタデータ)が返されます。
bigquery://easypost-platform.DORA.ai_attribution
ワークフロー(MCP)
list_datasets→ データセットを検出します(URI の一覧を返します)list_tables→ テーブルを調べます(URI の一覧を返します)- リソース
bigquery://project.dataset.tableを読み取る → スキーマを取得します dry_run→ コストを見積もりますquery→ クエリを実行します
MCP 設定
{
"mcpServers": {
"bigquery": {
"command": "bigquery",
"args": ["mcp", "stdio"]
}
}
}
追記専用の raw テーブルパターン
table_raw— 追記専用の書き込み先。インプレースで UPDATE/DELETE しないでくださいtable(VIEW)— 読み取り用のビュー。ROW_NUMBER() OVER (PARTITION BY <key> ORDER BY loaded_at DESC) = 1を使用して重複を排除します- 常に
loaded_at TIMESTAMP REQUIREDを含め、書き込み時にCURRENT_TIMESTAMP()を設定してください - レコードを「更新」するには、修正した値と新しい
loaded_atを設定した行を INSERT してください - DML の対象に VIEW を指定しないでください。必ず raw テーブルに書き込んでください
データの書き込み — 挿入と読み込みのパターン
A:tables load はローカルファイルのパスを無視します
bigquery tables load には Cloud Storage URI(gs://...)が必要です。ローカルパスを渡すと、終了コード 0 で何も出力されません。テーブルには書き込まれず、後続の読み取り結果は 0 行になります。ローカルファイルには tables insert を使用してください。
B:ストリーミング挿入コマンド
bigquery tables insert --format jsonl --yes <project.dataset.table> <local-file.jsonl>
bigquery insert(tables なし)は存在せず、「unknown command」が返されます。ファイルは JSONL 形式である必要があります。--yes を指定すると、コスト確認のプロンプトをスキップします。
C:新しいテーブルの反映遅延
bigquery tables create の後、メタデータの反映には最大で約 50 秒かかります。直後に tables insert を呼び出すと、「Not found: Table」エラーが返されます。挿入処理をリトライループで囲んでください。
for attempt in range(10):
result = subprocess.run([...tables insert...], capture_output=True, text=True)
if result.returncode == 0:
break
if "Not found" in result.stderr:
time.sleep(5)
continue
raise RuntimeError(result.stderr)
else:
raise RuntimeError("table not available after 50s")
D:ストリーミングバッファにより、DELETE/TRUNCATE が約90分間ブロックされます
ストリーミング挿入後に DELETE FROM table WHERE TRUE および TRUNCATE TABLE を実行すると失敗します。
UPDATE or DELETE statement over table would affect rows in the streaming buffer, which is not supported
この状態は最大90分間続きます。WRITE_TRUNCATE のセマンティクス(実行のたびにすべての行を置き換える)にするには、削除して再作成します。
subprocess.run(["bigquery", "tables", "delete", table], capture_output=True)
_ensure_table(table) # recreate with schema
# propagation delay applies after recreate — use retry loop from (C)
既知の注意点
JSONL 出力の DATE 列は、文字列ではなく {"value": "YYYY-MM-DD"} の辞書を返します。TIMESTAMP 列は ISO 形式の文字列ではなく、エポック秒を表す浮動小数点数の文字列("1.760730316667E9")を返します。
def _parse_date(v) -> str:
if isinstance(v, dict): return str(v["value"])[:10]
return str(v)[:10]
def _parse_ts(v) -> datetime:
try: return datetime.fromisoformat(str(v))
except ValueError: return datetime.fromtimestamp(float(v), tz=timezone.utc)
数値列は文字列として渡されます。 集計する前にキャストしてください。
df["col"] = pd.to_numeric(df["col"], errors="coerce").fillna(0).astype("int64")
carrier_accounts の結合による行の増幅:ep-core-data.raw.carrier_accounts には重複した ID が約77K件あります。結合する前に、必ず SELECT DISTINCT id, ... で重複を排除してください。検証方法:結合後の COUNT() ≈ 結合前の COUNT()。
CTE/列エイリアスの衝突:CTE と列エイリアスが同じ名前の場合、BQ は ORDER BY col を CTE(STRUCT)として解決し、「Ordering by expressions of type STRUCT is not allowed」が発生します。列エイリアスの名前を変更してください。
ディメンション参照を事前に解決する:shipments(4.2TB)は user_id でクラスタ化されていません。SF アカウントで絞り込むために dim.users と結合すると、日付パーティション全体(77GB 以上)がスキャンされます。代わりに、まず低コストのクエリでディメンション ID を解決し、その後、ファクトテーブルで IN 句を使います。結合は不要です。
Salesforce の created_date は、Polytomic の同期タイムスタンプ(2025年2月以降)であり、SF での作成日ではありません。過去のクエリには close_date または SF 固有の日付フィールドを使用してください。
salesforce.tasks.created_date は INT64 のナノ秒です。TIMESTAMP_MILLIS(CAST(created_date / 1000000 AS INT64)) で変換してください。
UNNEST のリテラルサイズ制限:SQL 文字列内のリテラル配列として UNNEST([key1, key2, ...]) を使い、大量のキー(例:50k 件以上)を渡す SQL クエリを作成すると、bigquery CLI のサブプロセスが「Expecting ',' delimiter: line 1 column 1517」のような JSON 解析エラーで失敗します。SQL 自体は構文的に正しくても、CLI が入出力制限に達する可能性があります。
対処法:大量のキーセットを SQL リテラルに埋め込まないでください。代わりに、対象テーブルからすべての行を取得し(可能であれば REGEXP_CONTAINS などで事前に絞り込み)、Python 側でキーを照合します。これは extract_phab.py の _build_revision_lookup で使われている方法と同じです。すべてのリビジョンを取得し、Python でチケット参照を解析して、対象キーセットとの積集合を取ります。
クイックリファレンス
bigquery auth check
bigquery query --yes "SELECT ..."
bigquery dry-run "SELECT ..."
bigquery datasets list
bigquery tables list PROJECT.DATASET
bigquery tables describe TABLE
bigquery tables insert TABLE file.jsonl --format jsonl
bigquery tables load TABLE gs://bucket/file.csv --write-disposition WRITE_TRUNCATE
bigquery mcp stdio