Skip to content
/ Chapter 5 · Joins
Lesson 5.6 · garden_shop
Lesson 5.6

SQL CROSS JOIN

A CROSS JOIN pairs every row of one table with every row of another. It builds the full grid of combinations, which a LEFT JOIN can then fill in.

Every join so far matched rows on a condition. A CROSS JOIN has no condition: it pairs every row of the first table with every row of the second. Garden Shop has 6 suppliers and 8 categories, so crossing them gives 6 × 8 = 48 rows, one for every possible supplier and category:

Every supplier with every category
select s.supplier_name, c.category_name
from suppliers as s
cross join categories as c
order by s.supplier_name, c.category_name

There's no ON, because there's nothing to match. Most of those pairs never happen: no seed company sells tools. Listing them anyway is the point, and it solves a problem a normal join can't.

Zeros don't come from data

How many products does each supplier sell in each category?

Counting through ordinary joins
select s.supplier_name, c.category_name, count(*) as products
from suppliers as s
join products as p on p.supplier_id = s.supplier_id
join categories as c on c.category_id = p.category_id
group by s.supplier_name, c.category_name
order by s.supplier_name, c.category_name

That returns 11 rows, and none of them is a 0. Every row of the result comes from a product, so a pair with no products produces no row at all. For a report that says "Ironwood Tools sells nothing in Houseplants", the zeros are the answer, and the data can't supply them.

The fix comes in two steps. CROSS JOIN builds every pair the report should show. Then a LEFT JOIN to products attaches whatever matches each pair and keeps the pairs that match nothing. The ON clause needs both keys, p.supplier_id = s.supplier_id and p.category_id = c.category_id, because a product belongs to the pair only when it matches both. Count p.product_id, as in Lesson 5.3, and an empty pair counts 0. The exercise below does this for two suppliers.

The same grid-then-fill idea shows up in Lesson 21.2 · Date spines, where one side of the grid is a generated list of days, so a day with no orders still gets a row.

The CROSS JOIN you didn't mean

A cross join's row count is the two table sizes multiplied, and it grows fast. The old comma style of joining makes one easy to write by accident:

Two tables, no join condition
select count(*) as row_count
from customers, orders

20 customers times 24 orders is 480 rows, every customer paired with every order, including orders that belong to someone else. With a WHERE condition linking the two, the comma form works like an inner join; without one, it's a cross join that nobody asked for. DuckDB refuses a plain JOIN with no ON as a syntax error, which is one reason to write joins with the keyword. Writing CROSS JOIN when you mean it tells the next reader the missing condition is deliberate. The missing join predicate mistake page runs the broken query beside the fixed one.

Schema · Garden Shop Tables · suppliers, categories, products 3 tables
Table · suppliers

One row per supplier. Some suppliers have no contact email.

4 columns · 6 rows
supplier_id int supplier_name text contact_email text state text
Table · categories

Lookup table of product categories.

2 columns · 8 rows
category_id int category_name text
Table · products

One row per product, with price, cost, and inventory levels.

9 columns · 24 rows
product_id int product_name text category_id int supplier_id int price decimal cost decimal quantity_on_hand int reorder_level int discontinued bool
Your task

For Ironwood Tools and Terra Pots Co, show how many products each sells in every category, including the categories where the count is 0. Return supplier_name, category_name, and products, sorted by supplier, then category. The starter only finds the pairs that have products.

·

Run your query to inspect the result.

Expected answer
  • Columns: supplier_name, category_name, products.
  • 16 rows: all eight categories for each of the two suppliers. Ten of them are 0.
  • Ironwood Tools sells Tools, Watering, and Outdoor Decor; Terra Pots Co sells Pots & Planters, Outdoor Decor, and Watering.
← Previous · 5.5 FULL OUTER JOIN
End of Chapter 5

That's the last lesson in “Joins.”

The next chapter builds on what this one covered.

Start Chapter 6: CASE Logic and Derived Columns → Begins with 6.1 Calculated columns