CROSS JOIN
A CROSS JOIN pairs every row from one table with every row from another, producing what is called the Cartesian product of the two tables. Unlike every other join type covered in this section, a CROSS JOIN has no ON clause at all — there is no matching condition, because every possible pairing is included by definition. If table A has 4 rows and table B has 5 rows, a CROSS JOIN between them always produces exactly 4 x 5 = 20 rows.
Basic syntax
CROSS JOIN syntax
SELECT c.name, o.order_id FROM customers c CROSS JOIN orders o;
With 4 customers and 5 orders in the reference tables, this query returns 20 rows — every customer paired with every order, whether or not that customer actually placed it. That is rarely what you want with transactional data like customers and orders, which is exactly why CROSS JOIN is more useful for generating combinations than for querying related records.
Use case: generating all combinations
CROSS JOIN shines when you genuinely need every combination of two independent sets — for example, every size paired with every color for a product catalog, or every day in a date range paired with every store location for a reporting template.
Generating every size/color product variant
CREATE TABLE sizes (size VARCHAR(10));
CREATE TABLE colors (color VARCHAR(10));
INSERT INTO sizes (size) VALUES ('S'), ('M'), ('L');
INSERT INTO colors (color) VALUES ('Red'), ('Blue');
SELECT size, color
FROM sizes
CROSS JOIN colors;size | color -----+------ S | Red S | Blue M | Red M | Blue L | Red L | Blue
Six rows come out of three sizes and two colors (3 x 2), giving every variant combination in one query — far simpler than generating the same list by hand or in application code.
The classic "missing ON clause" bug
A missing join condition silently becomes a CROSS JOIN
-- Bug: no WHERE clause linking customers to orders. -- This does NOT error — it returns a Cartesian product (20 rows). SELECT c.name, o.order_id, o.amount FROM customers c, orders o; -- Fixed: the WHERE clause restores the intended join condition. SELECT c.name, o.order_id, o.amount FROM customers c, orders o WHERE c.customer_id = o.customer_id;
This is one of the strongest arguments for always using explicit JOIN ... ON syntax instead of the older comma-separated FROM list: with explicit JOIN syntax, forgetting the ON clause is a syntax error you catch immediately, rather than a silent correctness bug you might not notice until the numbers in a report look wrong.
CROSS JOIN produces the Cartesian product: every row from A paired with every row from B.
It has no ON clause, because there is no filtering condition — everything is included.
Useful for generating combinations, such as size/color variants or a date-dimension table.
Forgetting a join condition with old-style comma joins silently produces an accidental CROSS JOIN instead of an error.