Skip to content
technical guide

Query BigQuery in Plain English

Query BigQuery in plain English safely: the two-project model, the two IAM roles that scope reads, bytes-scanned cost guards, and partition-required tables.

By the Datarelix Team · Published

You can query BigQuery in plain English, and the two things that decide whether that is safe and affordable are both BigQuery-specific: access is granted through IAM roles rather than SQL GRANT statements, and cost is a function of bytes scanned rather than compute time. Grant two narrow roles, understand what a question can scan, and natural-language querying of BigQuery is a scoped read with a visible bill.

What you need in Google Cloud

Data engineers and analytics owners running BigQuery who are deciding whether to let people ask it questions in plain English — and who own the project the query bill lands on. It assumes you can assign IAM roles in the Google Cloud console. The field-by-field connection form, including where each credential comes from, is in the BigQuery connection guide.

Two projects, and the two roles that scope them

BigQuery separates where a query runs from where the data lives. A query job always runs — and bills — in your billing project; the tables it reads can sit in a different data project entirely. That split is what makes bigquery-public-data datasets queryable from your own account.

The read boundary is two IAM roles, each on the right project:

RoleWhere to grant itWhat it permits
BigQuery Data ViewerThe data project (or a single dataset)Reading table data and metadata
BigQuery Job UserThe billing projectRunning query jobs that your project pays for

Neither role can write, create, or delete anything. That makes the pair a boundary Google enforces on its side, before any request from any tool reaches your tables. On top of it sits the second boundary: every generated statement is parsed into a full syntax tree and rejected unless it is a read — the argument for why both layers exist is in read-only AI analytics.

One honest wrinkle for OAuth connections: Google’s consent screen shows the full bigquery scope, whose wording mentions managing data, because that is the scope required to run a query — a query creates a job. If you want the read restriction enforced by Google rather than only by the validator, connect with a service account carrying exactly the two roles above and nothing else.

The bill is bytes scanned, and the guards are real

On-demand BigQuery charges by the terabyte scanned, per Google’s pricing model. Because storage is columnar, SELECT * reads every column of every row touched — and, counter-intuitively, adding LIMIT 10 does not make it cheaper: the scan happens before the limit applies. Ad hoc questions generate more queries than a dashboard does, so the guards matter more, not less.

Three ship with Datarelix and are not configurable per question:

  • A per-query scan cap of 10 GB (maximum_bytes_billed). A question that would scan more is refused by BigQuery before a byte is billed — a runaway question against a multi-terabyte table costs nothing rather than a fortune.
  • A 30-second execution timeout per query.
  • A 5,000-row result cap, so an unbounded question cannot return an unbounded result.

Two are yours to set. Scope the connection to one modelled dataset rather than raw events — governed marts beat raw tables on both cost and correctness. And for a hard ceiling of your own, BigQuery supports custom query quotas per project and per user, which cap total daily bytes independently of any tool.

For the expected spend, the arithmetic is short:

cost/month  ≈  questions/day × avg bytes scanned per question × your region's on-demand rate × 30

The 10 GB cap bounds the worst term: whatever the table size, one question can never scan more than 10 GB. On a modelled, partitioned dataset, typical analytical questions scan megabytes.

Tables that refuse to run without a partition filter

BigQuery tables can be configured to require a partition filter — a query without a WHERE on the partition column is rejected outright, precisely to prevent accidental full scans. This is normally where generic text-to-SQL breaks: the model does not know the requirement exists and the query fails with an opaque error.

Datarelix reads partition metadata during discovery — the partition column, its type, and whether a filter is required, including ingestion-time partitioning where the partition column is a pseudo-column rather than a declared field — and includes the required filter when it generates the query. If you add a partition-required table later, re-run discovery so the requirement is picked up.

GoogleSQL specifics in the generated queries

BigQuery speaks GoogleSQL, and a system generating generic SQL produces statements it rejects. What actually shows up in generated queries:

  • Backticked three-part names`project.dataset.table` — because the data project is part of the address.
  • UNNEST for arrays and structs. BigQuery schemas lean on nested and repeated fields; questions over deeply nested structures are where generated SQL is least reliable, on this engine and every other.
  • TIMESTAMP vs DATETIME — the first is an absolute instant, the second civil time with no zone. A schema that mixes them invites wrong time-window answers no natural-language layer can rescue.
  • QUALIFY for filtering on window functions without a wrapping subquery.

Against the public names dataset, “How many babies were named Ada each year since 2000?” generates something like:

SELECT year, SUM(number) AS births
FROM `bigquery-public-data.usa_names.usa_1910_current`
WHERE name = 'Ada' AND year >= 2000
GROUP BY year
ORDER BY year;

The interpretations — exact-case name match, calendar years, births summed across states — are visible in the query, which is what makes the answer checkable: the routine is in how to verify an AI-generated data answer.

Constraints exist but are never enforced

BigQuery supports primary- and foreign-key constraints, but only as NOT ENFORCED metadata — and most datasets declare none at all. Discovery surfaces declared keys where they exist; where they do not, join paths are inferred from naming conventions, and inference is sometimes wrong. Check the joins in the first several answers on any dataset you did not model, and attach column descriptions where names are cryptic — why semantic context matters shows what that changes.

Connecting BigQuery to Datarelix

Three auth modes: Google Account (OAuth) — a per-connection consent popup, with the refresh token stored encrypted and scoped to that connection; Service Account Key (JSON) — the key stored encrypted, best for standing connections; and Service Account Impersonation. Signing in to Datarelix with Google grants identity only; authorizing a BigQuery connection is always a separate, explicit step.

The connection names a billing project, a location, and one allowed dataset in data-project.dataset form — an explicit dataset is required, and queries are restricted to it even where BigQuery’s SQL could reach further. The location must match the dataset’s region, or BigQuery reports the dataset as not found. Discovery uses the BigQuery API rather than INFORMATION_SCHEMA SQL, so public and cross-project datasets introspect cleanly. Setup steps and the troubleshooting table are in the BigQuery connection guide.

What does not work on BigQuery

One dataset per connection, so cross-dataset joins in a single question are out — create one connection per dataset instead. There is no write path of any kind: no DML, no DDL, no loading. Deeply nested STRUCT/ARRAY schemas are the weakest area for generated SQL. And the row cap means “export the table” is the wrong tool — that is a job for BigQuery itself.

Where these facts come from

Role definitions follow BigQuery access control; pricing behavior follows BigQuery pricing; location semantics follow BigQuery locations; partition-filter behavior follows partitioned table documentation. Product statements describe Datarelix as shipped in August 2026 and are stated canonically on the security page. The example query runs against Google’s public usa_names dataset.

Ask a public dataset a question first

Point a connection at bigquery-public-data.usa_names with your own project as the billing project — public data, two roles, nothing of yours exposed — then follow the quickstart and ask the question above. Read the generated SQL before the number. Your first 14 days run at Pro limits, no credit card required.