Google BigQuery

BigQuery SQL style and best practices: a short, tested standard

A short standard for BigQuery SQL that a team can adopt in one meeting: names, layout, reserved keywords and backticks, the three comment styles, raw and triple-quoted strings, SAFE functions, and the cost rules that matter most. Every syntax point was checked in BigQuery, including what fails, such as EXPLAIN.

Google BigQueryIevgen Krasovytskyi4 min read

BigQuery SQL style and best practices: a short, tested standard

A code standard is worth having when two people read each other’s queries. It does not need to be long. This page is a standard that fits on one screen, with each syntax rule checked in BigQuery, so it can be adopted as is or used as a starting point.

Area Rule
Names snake_case, singular tables, plural only for arrays
Layout one clause per line, one column per line, keywords in capitals
Reserved words avoid them as names; when unavoidable, backtick them
Comments -- for notes, /* */ for blocks
Strings raw strings for regex, triple quotes for multi-line text
Errors SAFE. and SAFE_ functions only where a NULL is acceptable
Cost name columns, filter partitions, check the estimate
Logic one definition per metric, shared, not copied

Note: Rewritten in October 2026. Every query and error message below was produced in BigQuery on 16 October 2026.

Names

Names

  • snake_case for everything: datasets, tables, columns, CTEs. BigQuery column names are not case-sensitive, so OrderDate and orderdate collide.
  • Datasets by stage and domain: raw_google_ads, staging_crm, reporting_marketing. The prefix says how far the data has been processed; the rest says what it is.
  • Tables singular, by grain: order, session, daily_channel_spend. The name answers “one row is one what”.
  • Columns say their unit: amount_usd, cost_micros, duration_seconds, is_paid for booleans, _at for TIMESTAMP and _date for DATE.
  • IDs end in _id and keep the same name in every table, so a join reads USING (customer_id).

Reserved words and backticks

Reserved words and backticks

SELECT 1 AS order;

fails with “Syntax error: Unexpected keyword ORDER”. ORDER, SELECT, GROUP, FROM and other reserved keywords cannot be used as plain names. With backticks they can: SELECT 1 AS `order` runs.

Not every SQL keyword is reserved in BigQuery. SELECT 2 AS date, 3 AS record ran without backticks. The safe rule is still to avoid them: a column called date reads ambiguously next to the DATE type and function. Use order_date, event_date.

Project IDs with a hyphen are a special case. In FROM, BigQuery accepts them unquoted: FROM my-project.dataset.table passed a dry run in our test. Outside FROM the same path fails with a syntax error, and other names with a hyphen need quoting anyway. Backtick the whole path, `my-project.dataset.table`, and the question never comes up.

The Turning Point

OWOX Data Marts

See your first report built in real time. 15 minutes.

  1. Connect your data warehouse
  2. Pick your metrics
  3. Get a live Google Sheets report

In the time it takes to write a ticket. Then imagine never writing that ticket again.

Book a Demo

We'll use your actual use case

Layout

Layout

SELECT
  customer_id,
  COUNT(*) AS orders,
  SUM(amount_usd) AS revenue_usd
FROM reporting_marketing.order
WHERE order_date >= '2026-09-01'
  AND status = 'paid'
GROUP BY customer_id
ORDER BY revenue_usd DESC;

One clause per line, one column per line, trailing commas avoided, conditions aligned under WHERE. The point is diffs: when a column is added, one line changes. Name every aggregate with AS; an unnamed one becomes f0_, which nobody downstream can read. Use CTEs for steps instead of nested subqueries; see the CTE guide.

Comments

Comments

All three styles work in BigQuery:

SELECT 1 AS n  -- a note at the end of a line
# also a single-line comment
/* a block
   comment */

Use -- for single lines; # works but is unusual outside BigQuery and confuses readers coming from other SQL. Comment the why, not the what: -- refunds are excluded because finance books them separately is useful; -- filter status is noise.

Strings

Strings

SELECT
  """He said "it's fine"
on two lines""" AS triple,
  r'\d+' AS raw_regex;
triple raw_regex
He said “it’s fine” (new line) on two lines \d+
  • Triple quotes hold quotes and line breaks without escaping: useful for JSON, long text and SQL inside SQL.
  • Raw strings, r'...', keep backslashes as typed. Write every regular expression as a raw string, or \d has to become \\d. The string functions guide has the regex functions.

SAFE functions

SAFE functions

Expression Result
SAFE.PARSE_DATE('%Y-%m-%d', '2026-13-01') NULL
SAFE_DIVIDE(1, 0) NULL

The SAFE. prefix turns an error into a NULL for most functions, and SAFE_DIVIDE, SAFE_CAST and others are their own functions. Use them where a NULL is an acceptable answer, and count the NULLs they produce; otherwise a broken input is replaced by silence. Not every function accepts the prefix: SAFE.DATE(string) fails with “SAFE with function … is not supported”. Details are in CAST and SAFE_CAST.

Cost rules

Cost rules

  1. Name the columns. On-demand queries are billed by the columns read; SELECT * on a wide table can cost hundreds of times more.
  2. Filter on the partition column with constants, so BigQuery prunes partitions. See partitioned tables.
  3. Check the estimate the editor shows before running. LIMIT does not lower it.
  4. There is no EXPLAIN. EXPLAIN SELECT 1 fails with “Statement not supported: ExplainStatement”. Use the dry-run estimate before, and the job’s Execution details after, to see where time and bytes went.

Prices and the billing model are in BigQuery pricing.

Enforce it with tools

Enforce it with tools

  • SQLFluff, with its BigQuery dialect, checks layout and naming in CI.
  • Version control for every query a report depends on, so a change has a diff and an author.
  • A review rule: no query reaches a shared report without a second reader.

One definition per metric

One definition per metric

Style makes a query readable. It does not stop two readable queries from defining “active customer” differently, and that is what makes reports disagree. The last rule of a standard is about ownership: each metric is written once and read everywhere. In OWOX Data Marts that query is a Data Mart with an owner and a description per column, and every sheet and dashboard reads it. OWOX Data Marts runs your SQL as written, in your own BigQuery project, and does not transform the data. More SQL foundations are in the BigQuery SQL guide.

Your New Normal

Turn your data into decisions.

Governed data marts give you the clean foundation ML needs to actually work.

  • No AI hallucinations
  • Analyst-governed definitions
  • Every number traces to SQL
Get started free

FAQ

Frequently Asked Questions

Which words are reserved in BigQuery?

SQL keywords such as SELECT, FROM, ORDER and GROUP cannot be used as plain names: SELECT 1 AS order fails with 'Unexpected keyword ORDER'. Wrap them in backticks to use them anyway. Some keywords are not reserved, such as DATE and RECORD, but naming a column date is still unclear.

Does BigQuery have EXPLAIN?

No. EXPLAIN SELECT 1 fails with 'Statement not supported: ExplainStatement'. Use the dry-run estimate before running a query and the job's Execution details afterwards to see where time and bytes went.

How do I write comments in BigQuery SQL?

Three styles work: -- and # for a single line, and /* ... */ for a block. Use -- for single lines, since # is unusual outside BigQuery, and comment why a rule exists rather than what the line does.

When should I use SAFE functions in BigQuery?

Where a NULL is an acceptable answer for a bad input: SAFE.PARSE_DATE returns NULL for an invalid date, SAFE_DIVIDE for a division by zero. Count the NULLs they produce. Not every function takes the SAFE. prefix: SAFE.DATE(string) fails.

How should I format BigQuery SQL for readability?

One clause per line, one column per line, keywords in capitals, every aggregate named with AS, and CTEs instead of nested subqueries. A one-line change then shows as a one-line diff.

What tools help keep BigQuery SQL consistent?

SQLFluff with its BigQuery dialect checks layout and naming in CI; version control gives every query a history; and a review rule that every query feeding a shared report has a second reader.

What naming conventions should I use in BigQuery?

snake_case everywhere, datasets named by stage and domain (raw_google_ads, reporting_marketing), tables named for their grain, columns that state their unit (amount_usd, cost_micros), and IDs with the same name in every table.

What are BigQuery code standards?

A team's agreed rules for writing BigQuery SQL: names, layout, comments, string literals, error handling and cost habits, so that anyone can read and review anyone else's query.

Who wrote this

Ievgen Krasovytskyi

Ievgen Krasovytskyi · Head of Marketing

Ievgen Krasovytskyi is the Head of Marketing at OWOX, leading strategy across content, SEO, product marketing, and AI-powered automation. With deep expertise in analytics infrastructure, data warehouses, and marketing technology, he builds systems that connect marketing performance to business outcomes. Ievgen writes about SaaS growth, analytics workflows, and the future of AI in marketing operations.