SQL notebooks
A tab made of cells instead of one editor. Each SQL cell runs on its own and its result becomes a table the cells below can query by name — so a long analysis becomes a chain of small, checkable steps instead of a 200-line WITH.
SELECT make, COUNT(*) AS vehicle_count FROM `ace-analytics.warehouse.vehicles` WHERE first_registered >= '2020-01-01' GROUP BY make
-- Aggregate by manufacturer using results from the vehicle_data cell SELECT make, SUM(vehicle_count) AS total_vehicles FROM vehicle_data GROUP BY make ORDER BY total_vehicles DESC
| make⏷ | total_vehicles⏷ | |
|---|---|---|
| 1 | FORD | 4252980 |
| 2 | VAUXHALL | 2130011 |
| 3 | HONDA | 616242 |
| 4 | MERCEDES-BENZ | 305002 |
| 5 | RENAULT | 248352 |
Creating one
- ⌘⇧E, or the caret next to New query in the sidebar → New notebook.
- ⌘K → New SQL notebook.
- From a query tab: the editor’s ⋯ menu → Convert to notebook. A multi-statement script becomes one cell per statement.
A new notebook has one empty SQL cell called query1.
Kinds of cells
The toolbar has Run All and three add buttons: + SQL, + Text, + Chart. The same buttons appear when you hover below the last cell.
| Kind | What it is |
|---|---|
| SQL | An editor with the same completions, diagnostics and cost footer as a query tab, and a results grid underneath |
| Text | Markdown — click to edit, click away to render |
| Chart | A bar, line, pie, scatter or heatmap over another cell’s result: pick Source Cell, Type, X Axis, Y Axis and an optional Group By |
Every SQL and chart cell has a name, shown in its header. Click it to change it. Names start with a letter and contain only letters, digits and underscores; duplicates are refused. Cells are auto-named query1, chart1, note1, …
Cell header buttons: run, collapse, focus (opens the cell full-width; close it with the button at the top), move up, move down, a ⋯ menu with Copy to clipboard and Duplicate, and delete (with Undo). Cells can also be dragged by their handle to reorder.
Running cells
| Action | How |
|---|---|
| Run this cell | The ▶ in the cell header, or ⌘Enter in its editor |
| Run this cell and everything that depends on it | Shift-click ▶, or ⌘⇧Enter |
| Run every SQL cell, top to bottom | Run All — stops at the first cell that fails |
Each cell runs as its own BigQuery job, with its own dry-run and its own byte limit. If any cell is over its limit, Run All asks before starting.
Referencing other cells
Write the upstream cell’s name where a table would go:
SELECT d.make, d.model, COUNT(*) AS defects FROM make_summary AS m JOIN `ace-analytics.warehouse.defects` AS d ON d.make = m.make GROUP BY d.make, d.model
When a SELECT cell finishes, BigQuery has written its result to an anonymous table. Querylab.io remembers that table and, when a later cell runs, swaps FROM make_summary for the real reference (something like `my-project._script7f3a.anon9c1e`) before sending the job. Nothing is re-executed; the downstream cell reads the stored result.
- The upstream cell has run in this session, or its result table still exists from a previous one — anonymous tables live about 24 hours
- The upstream cell is a SELECT. CREATE, INSERT, MERGE, DECLARE and other statements don’t produce a result table
- The reference is directly after FROM or JOIN
If you reference a cell that hasn’t run, the feedback bar says so before you waste a job: Cell “make_summary” has not been executed yet. Run it first. Upstream cells are never run for you.
Completions know cell names: after FROM, cells are offered like tables, and once a cell has run its result columns are offered too.
Stale cells
Edit, re-run, rename, move or delete a cell and every cell that reads from it gets a Stale marker in its header, with the reason on hover. Its old results stay visible; click the marker to re-run.
Variables
Two kinds, both flowing downward from the cell that defines them.
DECLARE variables are ordinary BigQuery scripting variables. A cell that uses one without declaring it gets the declaration prepended at run time:
DECLARE start_date DATE DEFAULT '2025-09-01'; DECLARE min_tests INT64 DEFAULT 100;
SELECT make, COUNT(*) AS tests FROM `ace-analytics.warehouse.mot_tests` WHERE completed_date >= start_date GROUP BY make HAVING tests >= min_tests
Template variables are plain assignments in a cell of their own. A cell that contains nothing else is skipped when run — it exists only to be read.
table_name = 'mot_tests'; result = 'FAILED';
SELECT make, COUNT(*) AS failed FROM `ace-analytics.warehouse.{{ table_name }}` WHERE test_result = @result GROUP BY make
{{ name }} is a text substitution, so it works for identifiers — tables, columns, project IDs. @name becomes a real query parameter (always STRING), which is what you want for values: it can’t break the SQL and BigQuery can cache the result. A missing @name fails before the job is sent, naming the variable to define.
Cost and billing per cell
The tune icon in the toolbar opens Notebook Configuration; the one in a cell header opens Cell Configuration. Both have the same fields:
TABLESAMPLE isn’t a hidden setting: it is written into the cell’s SQL as a directive comment, so you can see and edit it. Setting it at notebook level applies it to every cell that hasn’t set its own. See TABLESAMPLE.
Getting the SQL out
The toolbar’s ⋮ menu:
- Copy SQL as CTEs — one statement: every SELECT cell but the last becomes
name AS (…)in aWITH, the last is the body. DECLARE and DDL cells go in front as-is. - Copy SQL as temp tables — a script:
CREATE TEMP TABLE name AS (…);per cell, the last SELECT unchanged,DROP TABLE IF EXISTSlines at the end. - Copy to clipboard — the cells as JSON. Paste into any notebook (⌘V with the notebook focused) to append them; a single cell’s ⋯ → Copy to clipboard does the same for one cell.
Both SQL exports show a toast with Open in new tab, which drops the generated SQL into a fresh query tab. Template-variable cells are left out; the variables aren’t substituted, so fill them in before running.
A cell’s results grid has the usual export options; the BigQuery and Cloud Storage ones add a new SQL cell with the CREATE TABLE or EXPORT DATA statement instead of opening a tab.
Share Notebook creates an encrypted link to the whole notebook — cells, text, chart configs. Billing projects and destination tables are stripped. See Sharing.