Docs /SQL Editor /Code quality
SQL EditorChecks

Code quality

The editor checks every statement as you type: syntax, unknown columns, aggregation mistakes, and the BigQuery cost traps a dry run won't tell you about. Problems get a squiggle, a hover explanation, and usually a one-keystroke fix.

Query 1
1234
SELECT *
FROM `ace-analytics.warehouse.fact_mot_test`
WHERE completed_date >= '2024-01-01'
LIMIT 10

SELECT * from large table ‘ace-analytics.warehouse.fact_mot_test’ (506.7GB). Consider selecting specific columns to reduce costs. sql-best-practices(select-star-large-table)



View Problem (Alt+F8) · Quick Fix… (Ctrl+.)

Reading a squiggle

UnderlineSeverityMeans
RedErrorBigQuery will reject this
OrangeWarningRuns, but costs more or does something you probably didn’t mean
BlueInfoWorth knowing; no action required
NoneHintShown only in the quick-fix menu when the cursor is on the code

Hover an underline for the message; every message ends with the rule id in parentheses. ⌥F8 (AltF8 on Windows and Linux) jumps to the next problem. Hint-level rules draw nothing; the lightbulb in the gutter is the only sign of them.

Some problems are found as you type; others come back from BigQuery’s dry run when you pause. Dry-run errors, like a missing required partition filter, also land in the status bar:

⚙ !Error Cannot query over table 'ace-analytics.warehouse.fact_mot_test' without a filter over column(s) 'completed_date' Fix with AIExplain ▷ Run Query

Fix with AI hands the error and the query to Prism AI; Explain asks it to explain the message. A syntax error shows the dry-run wording, Syntax error: Unexpected identifier "SELEC" at [1:1], with No quick fixes available.

Quick fixes

Put the cursor on the underlined code and press ⌘. (Ctrl. on Windows and Linux), or click the lightbulb. Enter applies the highlighted fix.

Quick Fix
1234567891011
WITH tests AS (
SELECT make, test_result
FROM `ace-analytics.warehouse.fact_mot_test`
),
vehicles AS (
SELECT make, model
FROM `ace-analytics.warehouse.dim_vehicle`
)
SELECT make, test_result
FROM tests
JOIN vehicles USING (make)

The menu always ends with two entries: Disable ’…’ rule, which switches that rule off in settings (not offered for syntax errors or rules your organization locks), and Fix with Prism AI, which sends the problems and their suggested fixes to the agent.

Fixes you’ll meet most:

RuleFix inserted
SELECT * on Large TableExpand SELECT * to explicit columns
Missing Partition Filter / Missing Cluster FilterAdd column filter: a WHERE condition on the partition or cluster column
Missing LIMIT on Large TableAdd LIMIT 1000 (or |> LIMIT 1000 in pipe syntax)
Wildcard Table Scan Without FilterAdd _TABLE_SUFFIX filter: today only, last 7 days, last 30 days
Large Table ScanAdd TABLESAMPLE SYSTEM (1 PERCENT); see TABLESAMPLE
Undefined Column / Table Alias / CTEDid you mean ’…’? (nearest name, STRUCT fields marked)
Ambiguous Column ReferenceQualify with ‘alias.column’
Non-Aggregated ColumnAdd ‘column’ to GROUP BY · Use GROUP BY ALL
Aggregate in WHEREChange WHERE to HAVING · Move aggregate condition to existing HAVING
NULL Comparison with EqualsReplace with IS NULL / IS DISTINCT FROM
COUNT(DISTINCT) PerformanceReplace with APPROX_COUNT_DISTINCT
Cross Join DetectedUse explicit CROSS JOIN · Move condition to ON clause
Unused CTERemove unused CTE ‘name’
Suggest QUALIFY / LIKE ANY / GROUP BY ALL / UNION BY NAMEConvert to QUALIFY clause · Replace with LIKE ANY · Use GROUP BY ALL · Use UNION BY NAME

The same menu also lists refactorings that don’t need a warning: expand t.*, extract a subquery to a CTE, inline a CTE, convert CROSS JOIN to INNER JOIN, flip JOIN sides, CASE → COALESCE / NULLIF, convert pipe syntax to standard SQL. Keyword casing and backtick cleanup live on the editor toolbar instead.

Suggest QUALIFY

The subquery + WHERE rn = 1 idiom has a shorter form. Offered for ROW_NUMBER(), RANK() and DENSE_RANK():

123456
SELECT * FROM (
SELECT vehicle_id, test_result,
  ROW_NUMBER() OVER (PARTITION BY vehicle_id ORDER BY completed_date DESC) AS rn
FROM `ace-analytics.warehouse.fact_mot_test`
)
WHERE rn = 1
123
SELECT vehicle_id, test_result
FROM `ace-analytics.warehouse.fact_mot_test`
QUALIFY ROW_NUMBER() OVER (PARTITION BY vehicle_id ORDER BY completed_date DESC) = 1

Suggest LIKE ANY

1
WHERE make LIKE 'FORD%' OR make LIKE 'VAUXHALL%' OR make LIKE 'MINI%'

becomes WHERE make LIKE ANY ('FORD%', 'VAUXHALL%', 'MINI%'). NOT LIKE … AND NOT LIKE … becomes NOT LIKE ANY.

Tuning thresholds and switching rules off

Settings → Code Quality (also listed under Settings). Two sections: Cost Optimization holds the thresholds, Diagnostic Rules the on/off switch for every rule.

Cost OptimizationControl warnings for expensive query patterns and missing filters
⌃
Query Pattern Warnings
Warn about SELECT * on tables larger than 1 GB
Show warnings when using SELECT * on large tables that could scan excessive data.
Warn about missing LIMIT on tables larger than 1 GB
Show warnings when queries lack LIMIT clause on large tables.
Warn about scanning tables larger than 100 GB
Show warnings when querying very large tables without filters.
Partition & Clustering
Warn about missing partition filtersAlert when querying partitioned tables without filtering the partition column (critical for BigQuery cost optimization).
Warn about missing cluster filtersAlert when querying clustered tables without filtering cluster columns (improves query performance).

The size choices are 100 MB / 1 GB / 10 GB (10 GB / 100 GB / 1 TB for the scan threshold) and Never warn. Sizes are decimal (1 GB = 10⁹ bytes) and compare against the table’s stored size.

The Diagnostic Rules section lists the rules below with a switch each, Enable All / Disable All per group, and an Enable All Rules button with a N rules disabled badge. Severities are fixed. In an organization, an admin can lock rules on (they show an Org policy badge), raise a rule’s severity, and set thresholds; the stricter of yours and the org’s applies.

Rules by category

All rules are on by default. The groups match the Diagnostic Rules section in settings.

Performance

RuleSeverityCatches
SELECT * on Large TableWarningSELECT * on a table above the threshold
Missing Partition FilterWarningPartitioned table with no filter on the partition column
Missing Cluster FilterWarningClustered table with no filter on a cluster column
Missing LIMIT on Large TableInfoNo LIMIT on a large table
ORDER BY Without LIMITWarningSorting a large table with no LIMIT, the “Resources exceeded” case
Wildcard Table Scan Without FilterWarningtable_* with no _TABLE_SUFFIX filter
Large Table ScanHintTable above the scan threshold, no filter, no sampling
Join with OR ConditionWarningON a = b OR c = d
Cross Join DetectedInfoExplicit or comma cross join
COUNT(DISTINCT) PerformanceHintCOUNT(DISTINCT x) where an approximation would do
Clustering Order SuboptimalHintWHERE conditions out of clustering-key order

Code Quality

RuleSeverityCatches
Unused CTEWarningA CTE nothing references
Duplicate CTEErrorTwo CTEs with one name
Duplicate Column AliasWarningThe same alias twice in a SELECT list
Suggest QUALIFY ClauseHintSubquery wrapper around a window function
Suggest GROUP BY ALLHintA GROUP BY that just repeats the non-aggregated columns
Suggest UNION BY NAMEHintUNION arms with the same columns in a different order
Suggest LIKE ANYHintChained LIKE … OR LIKE … on one column

Correctness

RuleSeverityCatches
Non-Aggregated ColumnErrorColumn neither grouped nor aggregated
Aggregate in WHEREErrorWHERE SUM(x) > 0
Nested AggregateErrorSUM(COUNT(x))
Non-Boolean WHEREErrorWHERE user_id
NULL Comparison with EqualsError= NULL, <> NULL
Missing Join ONErrorJOIN with no ON
Missing Join ConditionErrorJOIN whose condition doesn’t relate the tables
ORDER BY Not in SELECTErrorWith DISTINCT
ORDER BY Invalid PositionErrorORDER BY 0
ORDER BY Position Out of RangeErrorORDER BY 5 with four columns
CASE Type InconsistencyWarningBranches of different types
Conflicting Column AliasWarningAlias that shadows a column
Multi-level aggregationErrorThe forms BigQuery rejects

Semantic

RuleSeverityCatches
Undefined ColumnErrorColumn not in any table in scope
Undefined Table AliasErrorx.col where x isn’t declared
Ambiguous Column ReferenceWarningUnqualified name present in two joined tables
Ambiguous Star ExpansionWarningBare * over a JOIN
Duplicate ColumnWarningTwo result columns with one name
String in Numeric ComparisonWarningodometer > '1000'
Invalid Hierarchical NameErrorNot project.dataset.table

Parser & Engine holds the syntax error itself and ON After Comma Cross-Join. The Charts (ggsql) and Graph (GQL) groups hold the rules described on the Charts and Graph queries pages.

Reusable column aliases

BigQuery can let a SELECT alias be read by later items and by the WHERE of the same query, but only when the project option reusable_column_aliases_mode is on. The editor asks BigQuery whether it is on for the project and location of the active tab, with a free dry run, and follows the answer. With the option on, SELECT x * 2 AS y, y + 1 is not flagged, completions and hover know the aliases, and the cases BigQuery refuses (a duplicate alias that is read, an alias in the WHERE of a grouped query) are errors. With it off, the read is an unrecognized name. See Reusable column aliases in BigQuery for how to turn the option on and what it allows.

What the checks need

  • Schema loaded for the tables in FROM; column rules and size thresholds are silent otherwise
  • dbt and Dataform files are checked on the resolved SQL, so ref() and {{ … }} don’t count as syntax errors