---
title: "BigQuery SQL best practices: a short, tested style guide"
canonical: "https://www.owox.com/blog/articles/bigquery-code-standards-best-practices"
updated: "2026-10-16"
---

# 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 BigQuery](/blog/topics/bigquery) · Updated October 16, 2026 · [Ievgen Krasovytskyi](/team/ievgen-krasovytskyi) · 4 min read

![BigQuery SQL style and best practices: a short, tested standard](https://cdn.owox.com/www/content-marketing-article/bigquery-code-standards-best-practices/thumbnail-20261016124441.png/public)

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

*   **`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

```
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](/book-a-call)

We'll use your actual use case

## 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](/blog/articles/bigquery-cte-efficient-queries).

## 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

```
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](/blog/articles/string-functions-bigquery) has the regex 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](/blog/articles/bigquery-cast-and-safe-cast).

## 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](/blog/articles/bigquery-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](/blog/articles/bigquery-pricing).

## 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

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](https://www.owox.com/app-signup) 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](/blog/articles/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](https://www.owox.com/app-signup)

## 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](https://cdn.owox.com/www/webflow/68404586b341508a789a4aa5_.png/public)

[Ievgen Krasovytskyi](/team/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.

[LinkedIn](https://www.linkedin.com/in/ievgen-krasovytskyi-a38a1253/) · [All articles](/team/ievgen-krasovytskyi)

[Google BigQuery](/blog/topics/bigquery)

## Related articles

[Google BigQuery · BigQuery Date Functions: Syntax, Examples and Common Errors · October 6, 2026](/blog/articles/bigquery-date-functions)

[Google BigQuery · How to Connect GA4 to BigQuery: Setup, Limits and First Queries · October 6, 2026](/blog/articles/google-analytics-4-to-bigquery-guide)

[Google BigQuery · BigQuery String Functions: Syntax and Tested Examples · October 6, 2026](/blog/articles/string-functions-bigquery)

[See all articles →](/blog/articles)

## Book a call

You are booked. The invitation is on its way to , with the calendar invite and the meeting link.

[Reschedule](#)

[Cancel](#)

## Schedule a meeting

You are booked. The invitation is on its way to , with the calendar invite and the meeting link.

[Reschedule](#)

[Cancel](#)

## Links

Pages this page links to, on this site and on docs.owox.com. Where the page has a Markdown twin, its address follows the link.

- [Google BigQuery](https://www.owox.com/blog/topics/bigquery) — /blog/topics/bigquery.md
- [Ievgen Krasovytskyi](https://www.owox.com/team/ievgen-krasovytskyi) — /team/ievgen-krasovytskyi.md
- [Book a Demo](https://www.owox.com/book-a-call) — /book-a-call.md
- [CTE guide](https://www.owox.com/blog/articles/bigquery-cte-efficient-queries) — /blog/articles/bigquery-cte-efficient-queries.md
- [string functions guide](https://www.owox.com/blog/articles/string-functions-bigquery) — /blog/articles/string-functions-bigquery.md
- [CAST and SAFE_CAST](https://www.owox.com/blog/articles/bigquery-cast-and-safe-cast) — /blog/articles/bigquery-cast-and-safe-cast.md
- [partitioned tables](https://www.owox.com/blog/articles/bigquery-partitioned-tables) — /blog/articles/bigquery-partitioned-tables.md
- [BigQuery pricing](https://www.owox.com/blog/articles/bigquery-pricing) — /blog/articles/bigquery-pricing.md
- [OWOX Data Marts](https://www.owox.com/app-signup)
- [BigQuery SQL guide](https://www.owox.com/blog/articles/bigquery-sql-guide) — /blog/articles/bigquery-sql-guide.md
- [Google BigQuery · BigQuery Date Functions: Syntax, Examples and Common Errors · October 6, 2026](https://www.owox.com/blog/articles/bigquery-date-functions) — /blog/articles/bigquery-date-functions.md
- [Google BigQuery · How to Connect GA4 to BigQuery: Setup, Limits and First Queries · October 6, 2026](https://www.owox.com/blog/articles/google-analytics-4-to-bigquery-guide) — /blog/articles/google-analytics-4-to-bigquery-guide.md
- [See all articles →](https://www.owox.com/blog/articles) — /blog/articles.md
