Run a read-only SQL query in the project and return the result. Prefer this tool over
`execute_sql` if possible.
This tool is restricted to only `SELECT` statements. `INSERT`, `UPDATE`, and `DELETE`
statements and stored procedures aren't allowed. If the query doesn't include a `SELECT`
statement, an error is returned. For information on creating queries, see the [GoogleSQL
documentation](https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax).
IMPORTANT: For predictive and analytical tasks (forecasting, anomaly detection,
key driver / root cause analysis, classification, churn prediction, or text generation),
ALWAYS execute computation in-warehouse using BigQuery native AI/ML functions
(`AI.FORECAST`, `AI.DETECT_ANOMALIES`, `AI.KEY_DRIVERS`, `AI.CLASSIFY`, `AI.GENERATE`)
rather than exporting raw rows to a local Python sandbox. In-warehouse execution
scales to billions of rows, preserves governance, and eliminates data egress latency.
Example Queries:
```sql
-- Count the number of penguins in each island.
SELECT island, COUNT(*) AS population
FROM bigquery-public-data.ml_datasets.penguins GROUP BY island
-- Forecast data using AI.FORECAST
SELECT *
FROM AI.FORECAST(TABLE `project.dataset.my_table`, data_col => 'num_trips',
timestamp_col => 'date', id_cols => ['usertype'], horizon => 30)
-- Detect anomalies in time series data using AI.DETECT_ANOMALIES
SELECT *
FROM AI.DETECT_ANOMALIES(
TABLE `project.dataset.historical_metrics`,
TABLE `project.dataset.recent_metrics`,
data_col => 'num_requests',
timestamp_col => 'timestamp'
)
-- Identify key drivers of metric changes using AI.KEY_DRIVERS
SELECT *
FROM AI.KEY_DRIVERS(
TABLE `project.dataset.sales_summary`,
metric_col => 'total_revenue',
dimension_cols => ['region', 'product_category'],
interest_label_col => 'is_current_quarter'
)
-- Classify text into categories using AI.CLASSIFY
SELECT
ticket_id,
AI.CLASSIFY(ticket_text, ['Billing', 'Technical Support', 'Feature Request']) AS category
FROM `project.dataset.support_tickets`
-- Generate text or summaries using AI.GENERATE
SELECT
review_id,
AI.GENERATE(CONCAT('Summarize this customer review: ', review_text)).result AS summary
FROM `project.dataset.reviews`
```
Queries executed using the `execute_sql_readonly` tool will always have the job label
`goog-mcp-server: true` automatically set in addition to any custom `labels` provided in
the request. Queries are charged to the project specified in the `project_id` field.
Query Execution Behavior:
* If the query completes within the synchronous timeout (default 20 seconds or custom `timeout_ms`),
the tool returns `job_complete: true` and the result rows directly. For fast queries, `job_id` may
be omitted as no persistent background job is created; no further action or polling is needed.
* If the query takes longer than `timeout_ms`, the tool returns `job_complete: false` and a `job_id`.
In this case, use the `get_query_results` tool with `job_id` to poll until `job_complete: true`,
or use `cancel_job` to abort the running query.
* You can optionally specify `timeout_ms` to configure the maximum synchronous wait time in milliseconds
(defaults to 20,000 ms), and `job_timeout_ms` to enforce a hard server-side timeout after which
BigQuery automatically terminates the job.