SQL JOIN Visualizer
SQL JOIN visualizer online. See INNER, LEFT, RIGHT, FULL, CROSS, SEMI, and ANTI joins with sample tables and result rows. Free SQL join explainer.
Sample data stays the same so you can compare join types. Users 1–3 on the left, orders on the right (including an order for missing user 4).
users
| id | name |
|---|---|
| 1 | Alice |
| 2 | Bob |
| 3 | Carol |
orders
| id | user_id | total |
|---|---|---|
| 10 | 1 | 20 |
| 11 | 1 | 35 |
| 12 | 4 | 50 |
Match
SQL
SELECT u.id AS user_id, u.name, o.id AS order_id, o.total
FROM users u
INNER JOIN orders o ON o.user_id = u.id;Result (2 rows)
| user_id | name | order_id | total |
|---|---|---|---|
| 1 | Alice | 10 | 20 |
| 1 | Alice | 11 | 35 |
Features
- Interactive INNER, LEFT, RIGHT, FULL, CROSS, SEMI, and ANTI joins
- Fixed sample tables so the result is predictable
- Generated SQL you can copy
- Venn-style match highlighting
- Result grid with NULLs called out
- Runs entirely in this tab
Common Use Cases
- Teach INNER vs LEFT JOIN with a concrete example
- Remember why FULL OUTER JOIN needs NULLs on both sides
- See NOT EXISTS (anti join) vs LEFT JOIN ... IS NULL
- Explain CROSS JOIN row counts before someone ships one
Joins combine row sets
A JOIN matches rows from two tables. INNER keeps matches only. LEFT keeps every left row (NULL on the right when nothing matches). RIGHT is the mirror. FULL OUTER keeps both leftovers. CROSS is a cartesian product: no ON clause, row count multiplies.
SEMI (EXISTS) returns left rows that have at least one match, once. ANTI (NOT EXISTS) returns left rows with no match. MySQL 8 and Postgres 15+ also have matching JOIN syntax in some engines; EXISTS works everywhere.
Examples
FROM users u INNER JOIN orders o ON o.user_id = u.idFROM users u WHERE NOT EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id)Frequently Asked Questions
INNER JOIN drops left rows with no match. LEFT JOIN keeps them and fills right-hand columns with NULL. Toggle the visualizer to see Alice (has orders) vs Bob (none).
SQLite 3.39+ supports RIGHT and FULL OUTER JOIN. Older builds do not. Rewrite RIGHT as a LEFT with the tables swapped if you need to support old SQLite.
When you only need to know a match exists, not the matching rows. EXISTS (semi join) avoids duplicating the left row per match.
Tips
- Filter the right table in ON, not WHERE, if you want a LEFT JOIN to stay a left join. WHERE o.id IS NULL is the anti-join exception.
- CROSS JOIN of two large tables is how you lock up a database. Check counts first.