Documentation-based proposal; not a hands-on test
Translate the question into a data contract
Before reading SQL, write the requested population, date basis, unit of analysis, measure, and exclusions in plain language. “Revenue by customer last quarter” is incomplete until revenue basis, customer identity, time zone, refunds, and quarter boundaries are named. This contract becomes the checklist for the query.
Run exploratory work with read-only permissions where possible. PostgreSQL supports read-only transaction mode; BigQuery separates data-viewing access from query-job permissions and provides dry runs that validate a query and estimate processed data without running it. A dry run checks syntax and some planning concerns, not whether the result means what the user asked.
Inspect the query in six passes
- Base tables: confirm each table's grain and freshness.
- Joins: state expected cardinality for every join: one-to-one, many-to-one, or intentionally one-to-many.
- Filters: list inclusion and exclusion predicates in prose.
- Nulls: check whether missing values are excluded, retained, or converted.
- Dates: inspect boundaries, time zones, and which date column defines the period.
- Aggregation: confirm grouping columns and denominator.
PostgreSQL's join tutorial shows that a join builds rows from matching records across tables. That simple operation can multiply measures when the relationship is not what the author assumed. Count rows and distinct business keys before and after each important join. If 410 invoices become 1,247 rows after joining payments, summing invoice totals may triple-count them.
Make null behavior explicit
SQL null means unknown, not zero or an empty string. PostgreSQL documents that ordinary comparisons involving null return null, and recommends IS NULL or IS NOT NULL rather than = NULL. Check how nulls interact with filters and aggregates. A left join followed by a WHERE condition on the right-hand table can effectively remove unmatched rows. A COUNT(column) can differ from COUNT(*).
| Validation query | Purpose |
|---|---|
| Count rows and distinct keys | Detect multiplication or loss |
| Group by join key with count greater than one | Expose unexpected duplicates |
| Count nulls in filter and measure columns | Make missingness visible |
| Min and max date | Check period boundaries |
| Independent control total | Compare with a trusted source or simpler query |
Test slices, not just the final total
Choose a few known records and trace them from source to output. Compare a simple subgroup total with the production report or a reconciled spreadsheet. Reverse the question: list records excluded by each filter. Examine zero-result groups and unexpectedly large contributors.
Hypothetically, a query reports 90 active clients. A validation query finds 96 distinct client IDs before an inner join to account managers. The six missing clients have no current manager. The SQL is valid, but the answer silently changed from active clients to active clients with a manager. The correct fix depends on the question, not on syntax.
Preserve the answer's conditions
Save the exact SQL, execution timestamp, source snapshot or freshness note, row count, and validation results beside the narrative. Do not copy only the final number. If an assistant drafted the query, review it under the same process; generated SQL is a proposal.
For spreadsheet outputs, use the reconciliation guide. For generated code changes around the query, use the AI code-change review. The query is ready when a second person can see what population it measured and reproduce the checks that support the answer.
Before you hand it over
Use this as a working check, not certification. Checks stay in this page only and reset on reload.
0 of 5 checked
Sources & verification
Product details are based on the linked documentation. The proposed workflow and worked examples are editorial guidance, not measured test results.
- Run a querySource date: not stated · Retrieved: 2026-09-19T19:39:00Z
Dry runs validate query structure and estimate processed data; query jobs and table-data access use distinct permissions.
- START TRANSACTIONSource date: not stated · Retrieved: 2026-09-19T19:39:00Z
PostgreSQL transaction blocks can be declared READ ONLY.
- Comparison Functions and OperatorsSource date: not stated · Retrieved: 2026-09-19T19:39:00Z
Null comparisons yield unknown and should use IS NULL, IS NOT NULL, or distinctness predicates as appropriate.
- Joins Between TablesSource date: not stated · Retrieved: 2026-09-19T19:39:00Z
Join behavior and the construction of result rows from matching records across tables.
Continue the workflow
- Reconcile a spreadsheet before writing the story around it
Check an imported or transformed spreadsheet before using its figures in analysis or client work.
- Review an AI-assisted code change as a change, not a speed claim
Decide whether an AI-assisted patch is safe and maintainable without treating generation speed as evidence of quality.
- ChatGPT gained a firewalled Python sandbox for uploaded files
OpenAI's own materials describe Code Interpreter's July 2023 rollout as a sandboxed, firewalled Python environment for uploaded files.
- Snowflake keeps its SQL copilot's answers inside its perimeter
Snowflake's documentation states Cortex Analyst runs on models it hosts itself, so a query never leaves the account's governance boundary.