Local-first SQL reasoning workbench
Map the logic behind your SQL.
Paste a query and see its output grain, column lineage and join risk, computed from the SQL itself, in this tab, by a parser rather than a model.
The query runs. That is not the same as being right.
A LEFT JOIN with a WHERE clause on the right-hand table silently becomes an inner join. A GROUP BY you did not expect changes what one row means. A column you traced through four CTEs came from somewhere else entirely. None of it errors. All of it ships.
One query. Four ways to be sure of it.
Four tools, one query. Below, the same SQL is read as a route, moved to another dialect, measured against real files, and rebuilt from blocks.
SELECT c.segment, SUM(o.amount) AS revenue FROM customers c LEFT JOIN orders o ON o.customer_id = c.id WHERE o.status = 'paid' GROUP BY c.segment;
Paste a query; Atlas maps the route and reports the output grain, join risks, and column lineage before you trust the result.
Open AtlasSELECT c.segment, SUM(o.amount) AS revenue FROM customers c LEFT JOIN orders o ON o.customer_id = c.id WHERE o.status = 'paid' GROUP BY c.segment;
SELECT `c`.`segment`, SUM(`o`.`amount`) AS `revenue` FROM `customers` AS `c` LEFT JOIN `orders` AS `o` ON `o`.`customer_id` = `c`.`id` WHERE `o`.`status` = 'paid' GROUP BY `c`.`segment`
And when a construct really does change meaning:
SELECT first_name || ' ' || last_name AS full_name FROM customers
Passage moves the same query to another dialect and keeps every difference visible. Here there is nothing to warn about, and it says so; when a construct really does change meaning, it is named rather than silently rewritten.
Open PassageSELECT count(*) FROM read_csv('customers.csv') c
LEFT JOIN read_csv('orders.csv') o
ON o.customer_id = c.id AND o.status = 'paid'
WHERE o.customer_id IS NULL;Reads CSV, JSON, Parquet, Excel, Arrow, DuckDB
Survey reads your own files in this tab and measures what the other three can only ask about. Atlas can prove the LEFT JOIN is at risk; only the data can say what it costs.
Open SurveySELECT
c.segment,
SUM(o.amount) AS revenue
FROM customers AS c
LEFT JOIN orders AS o
ON o.customer_id = c.id
WHERE o.status = 'paid'
GROUP BY
c.segment;Draft assembles that same SELECT from structured blocks while the generated SQL stays visible and editable. The blocks below generate the query above, character for character.
Open DraftLocal-first, deterministic
Runs in your browser. SQL is not uploaded.
Parser and rules, not an LLM. The same query always maps the same way.
Dialects it reads
Full test corpus: PostgreSQL, MySQL, SQLite, SawitDB · Experimental: BigQuery, Snowflake
A LEFT JOIN that quietly loses customers.
Scroll to trace how one WHERE clause turns a LEFT JOIN into an inner join, and what Atlas reports about it.
Trace it in AtlasThe query
SELECT c.segment, SUM(o.amount) AS revenueFROM customers cLEFT JOIN orders o ON o.customer_id = c.idWHERE o.status = 'paid'GROUP BY c.segment;
The route
customers and orders flow through the join and filter into the grouped result.
The risk
The WHERE predicate filters orders, the right-hand side of the LEFT JOIN. Unmatched customers arrive with NULL order columns, fail the predicate, and disappear: the LEFT JOIN quietly behaves like an inner join.
LEFT_JOIN_WHERE_RIGHTThe consequence
Atlas flags the risky step (LEFT_JOIN_WHERE_RIGHT) and names the output grain: one row per segment.
Grain: one row per segmentWhat it knows, and what it cannot.
Every finding comes from parsing the SQL: one parser, one rule set, no model. The same query always produces the same answer, and each finding names the rule that raised it.
SQL alone cannot tell you whether a join key is unique, how many rows a filter drops, or whether a column is ever NULL in practice. Atlas will not guess at those. Survey measures them against your own files, and anything neither can prove is labelled unproven rather than asserted.
Built for analysts and engineers who inherit SQL they did not write, and have to be sure of it before it reaches a dashboard.
Field Notes
Release notes, fixes, and what I learned building SQLTerrain.