SQL Query Viewer

A teammate hands you a 60 line report query with five joins and a CTE on top. Paste the query below to see which tables feed which, what each join hangs on, and the order your database works through the clauses, before you touch a single line.

SQL query viewer workspace

Reviewed & Maintained by Wajahat Qasim Last updated October 4, 2026
Samples

Parsing runs in this browser tab. Your SQL is never sent anywhere or stored.

Statement
SELECT
Tables
4
Joins
3
Filters
2
Subqueries
0
Lines
14
S selected J join key F filtered G grouped O sorted W written Click a table to isolate its joins. Hover a line label for the full condition.

Joins, filters and sorting

Worth a second look

    Read a query by its tables, not its line order

    SQL puts the output first and the data source second. In a long report query the SELECT list fills the top half of the screen, the tables hide in the middle, and the join conditions sit next to tables they do not belong to. You end up scrolling up and down to answer one question: where does this number come from?

    The viewer answers by drawing the query instead of reformatting the text. Each table becomes a card listing only the columns this query touches, tagged by what the query does with them. Each join becomes a line from the parent table to the joined table, anchored on the actual key columns and colored by join type. The driving table sits on the left, and every hop to the right is one more join away from the start.

    Three situations where this view saves time:

    • Reviewing a pull request adding a fifth join to a reporting query. The diagram shows whether the new table attaches to the right parent, or to the line items, where the join multiplies row counts.
    • Reading ORM output from a Laravel or Django query log. Generated SQL arrives on one line with quoted identifiers everywhere. The cards strip the noise and show the shape.
    • Inheriting a database with no documentation. Paste the output of pg_dump --schema-only or mysqldump --no-data and the foreign keys come back as a schema map.

    Written order versus run order

    The database never reads your query top to bottom. Logically, the engine builds the row set first, then filters, then groups, and only then computes the SELECT list. The Run order tab lays out your own query in this sequence, with the written position next to each step.

    Run stepClauseWhat exists at this point
    1FROM and JOINRaw rows from every table, paired by the join conditions
    2WHEREIndividual rows. No groups, no output aliases
    3GROUP BYOne row per group. Ungrouped columns now need an aggregate
    4HAVINGGroups, so SUM() and COUNT() work here
    5SELECTOutput columns and their aliases, plus window functions
    6DISTINCTDuplicate output rows removed
    7ORDER BYAliases from step 5 are usable
    8LIMIT / OFFSETThe final slice handed back

    This table explains the most common SQL error people search for. Write WHERE revenue > 500 where revenue is a SELECT alias, and PostgreSQL replies with column "revenue" does not exist, while MySQL reports Unknown column 'revenue' in 'where clause'. The alias is born at step 5, three steps after WHERE runs. The review panel flags this before you hit run.

    One caution. This is the logical order, the one which decides what each clause sees. The query planner is free to reorder joins and push filters down for speed. For the physical plan, run EXPLAIN in PostgreSQL or MySQL, or turn on the actual execution plan in SQL Server Management Studio.

    What the review panel flags

    The checks look for patterns which run without errors and still return the wrong rows, or the right rows slowly. Each finding names the clause involved.

    A LEFT JOIN quietly turned into an INNER JOIN

    This one survives code review because the query looks right. A LEFT JOIN keeps stores with no reviews by filling the review columns with NULL. A WHERE filter on those columns then throws the NULL rows away, and the stores you meant to keep vanish.

    Drops stores with no reviews
    SELECT s.name, r.rating
    FROM stores s
    LEFT JOIN reviews r ON r.store_id = s.id
    WHERE r.rating >= 4;
    Keeps every store
    SELECT s.name, r.rating
    FROM stores s
    LEFT JOIN reviews r ON r.store_id = s.id
                       AND r.rating >= 4;

    Load the LEFT JOIN trap sample above to see the warning on a live query.

    The rest of the list

    • A join with no condition. A comma-separated table never tied to the others in WHERE, or a JOIN missing its ON. Two tables of 1,000 rows return 1,000,000. The Comma join sample shows one.
    • An output alias used in WHERE. Covered above. The query fails at run time on every major engine.
    • NOT IN over a subquery. One NULL in the subquery result makes the whole predicate unknown, and the query returns zero rows with no error. NOT EXISTS does not have this problem.
    • A function wrapped around a filtered column. WHERE YEAR(placed_at) = 2026 forces a calculation on every row and skips a plain index on placed_at. A date range does the same job with the index.
    • A leading wildcard. LIKE '%mart' has no prefix to seek on, so the database scans the full table.
    • LIMIT or TOP without ORDER BY. The rows you get depend on storage order and the plan of the day. Pagination built on this repeats and skips rows.
    • UPDATE or DELETE without WHERE. Flagged as an error, since the statement rewrites or empties the whole table.
    • An INSERT with no column list, which breaks the day someone adds a column to the target table.

    Paste CREATE TABLE statements for a schema map

    Give the viewer a script of CREATE TABLE statements and the diagram switches to schema mode. Every column shows its declared type, primary keys get a PK badge, and each foreign key draws a line from the referenced table to the referencing one. With more than one table in the script, a Whole schema entry appears first in the statement menu so you see every relationship on one board.

    Foreign keys added later through ALTER TABLE ... ADD FOREIGN KEY are picked up too, which matters for PostgreSQL dumps, since pg_dump writes constraints as separate ALTER statements after all the tables. A table referenced by a key but never created in the script still appears, with a dashed outline and a note, so a missing dependency is obvious before you run the script on an empty database.

    Load the Schema DDL sample to see four tables from an order system laid out by dependency: customers and products on the left, order lines on the far right.

    Where this viewer stops

    The viewer reads the text of your SQL. There is no database connection, which keeps your data private and also sets hard limits.

    • No schema knowledge. A column written without a table prefix in a multi-table query has no known owner, so the diagram leaves the column off and the review panel lists the name. Prefix every column with its alias and the cards fill in completely.
    • No row counts or indexes. The checks spot risky shapes. They have no idea whether orders holds 200 rows or 200 million, so a flagged leading wildcard on a tiny lookup table is harmless.
    • Subqueries stay closed. A subquery in FROM shows as one card with its output columns. Subqueries inside WHERE are counted, not drawn. CTEs get their own entry in the statement menu instead.
    • Procedural code is skipped. Function bodies in PL/pgSQL, T-SQL BEGIN ... END blocks, cursors and dynamic SQL built from strings fall outside the diagram. MERGE statements are listed without a drawing.
    • Big dumps slow the page. Every pause in typing re-reads the whole script. A schema of a few hundred tables is fine. A dump full of INSERT rows is not, so export with --no-data or --schema-only first.
    • Large diagrams get wide. Past roughly a dozen tables the board scrolls sideways. Use the statement menu or paste one query at a time for a tighter view.

    For layout only, without a diagram, the SQL Formatter rewrites the same query with consistent indentation.

    SQL viewer questions

    Privacy, dialects, and why a diagram sometimes looks thinner than the query.

    Does the viewer run my query or connect to a database?

    No. The SQL is parsed inside your browser tab and nothing reaches a server, so production queries with customer names or internal table names stay on your machine. In exchange, the viewer never sees real data, row counts or indexes.

    Which SQL dialects does the viewer read?

    MySQL, MariaDB, PostgreSQL, SQL Server, SQLite and the common Oracle syntax. Backtick, double quote and square bracket identifiers are all understood, along with PostgreSQL dollar quoted strings, MySQL hash comments, SQL Server TOP and CROSS APPLY, and LATERAL joins.

    Why are some columns missing from the table cards?

    Columns written without a table prefix in a query with two or more tables have no known owner. Only the database schema says whether status lives in orders or in customers. Those names appear in the review panel instead. Prefix them with the table alias and they move onto the right card.

    Is the run order the same as an execution plan?

    No. Run order is the logical sequence the SQL standard defines, which decides what each clause is allowed to see. The execution plan is the physical route the optimizer picked, often joining tables in a different order. For the plan, run EXPLAIN or EXPLAIN ANALYZE in PostgreSQL and MySQL, or enable the actual execution plan in SQL Server.

    How do I view one query out of a long script?

    Paste the whole script. With more than one statement present, a Show menu appears next to the counters. The menu lists every statement, each part of a UNION, and each CTE separately. The Highlighted SQL tab shades the statement currently on display.

    Why does my LEFT JOIN show a warning?

    A WHERE condition on the right-hand table of a LEFT JOIN removes the rows where no match was found, because their columns are NULL and NULL fails almost every comparison. The result matches an INNER JOIN. Move the condition into the ON clause to keep unmatched rows. Conditions using IS NULL or COALESCE are left alone, since they are usually deliberate.

    Is there a way to save the diagram?

    Not as a file yet. A screenshot of the diagram tab works for tickets and pull request comments. The diagram redraws from the SQL every time, so keeping the query text alongside the screenshot is the reliable way to reproduce the drawing.