SQLite CROSS JOIN

A CROSS JOIN combines every row from the first table with every row from the second table. It produces a result where the total row count equals the number of rows in table A multiplied by the number of rows in table B. This is called a Cartesian product.

The Cartesian Product Explained

Table A: colors        Table B: sizes
───────────────        ──────────────
color                  size
──────                 ──────
Red                    Small
Blue                   Medium
Green                  Large

CROSS JOIN result (3 × 3 = 9 rows):
────────────────────────────────────────
color │ size
──────┼────────
Red   │ Small
Red   │ Medium
Red   │ Large
Blue  │ Small
Blue  │ Medium
Blue  │ Large
Green │ Small
Green │ Medium
Green │ Large

CROSS JOIN Syntax

SELECT columns
FROM table_a
CROSS JOIN table_b;

-- Equivalent comma syntax (produces identical result):
SELECT columns
FROM table_a, table_b;

Practical Example: Product Variants

CREATE TABLE colors (color TEXT);
INSERT INTO colors VALUES ('Red'),('Blue'),('Green');

CREATE TABLE sizes (size TEXT);
INSERT INTO sizes VALUES ('Small'),('Medium'),('Large');

SELECT color, size,
       color || '-' || size AS variant_name
FROM colors
CROSS JOIN sizes
ORDER BY color, size;

color │ size   │ variant_name
──────┼────────┼─────────────
Blue  │ Large  │ Blue-Large
Blue  │ Medium │ Blue-Medium
Blue  │ Small  │ Blue-Small
Green │ Large  │ Green-Large
Green │ Medium │ Green-Medium
Green │ Small  │ Green-Small
Red   │ Large  │ Red-Large
Red   │ Medium │ Red-Medium
Red   │ Small  │ Red-Small

Real-World Use Cases

Use Case 1: Generate a Full Schedule Matrix

-- All employee + shift combinations
CREATE TABLE employees (name TEXT);
INSERT INTO employees VALUES ('Alice'),('Bob'),('Carol');

CREATE TABLE shifts (shift TEXT);
INSERT INTO shifts VALUES ('Morning'),('Evening'),('Night');

SELECT name, shift FROM employees CROSS JOIN shifts;

name  │ shift
──────┼────────
Alice │ Morning
Alice │ Evening
Alice │ Night
Bob   │ Morning
Bob   │ Evening
Bob   │ Night
Carol │ Morning
Carol │ Evening
Carol │ Night

Use Case 2: Price Grid

-- Every product × every region for a pricing table
SELECT p.name AS product, r.region, p.base_price
FROM products p
CROSS JOIN regions r
ORDER BY p.name, r.region;

Use Case 3: Number Series Generator

-- Generate numbers 1 through 9 using CROSS JOIN
WITH digits(n) AS (
  VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9)
)
SELECT a.n * 10 + b.n AS number
FROM digits a
CROSS JOIN digits b
WHERE a.n * 10 + b.n BETWEEN 10 AND 99
ORDER BY number;

Row Count Warning

CROSS JOIN grows fast:
──────────────────────────────────────────────────
Table A rows × Table B rows = Result rows
100    ×  100              = 10,000
1,000  ×  1,000            = 1,000,000
10,000 ×  10,000           = 100,000,000

A CROSS JOIN of two large tables can crash your query.
Always know the size of both tables before cross joining.

CROSS JOIN with WHERE Filter

Adding a WHERE clause to a CROSS JOIN filters the Cartesian product down to useful combinations.

-- All employee-shift pairs, but exclude Night shifts for Alice
SELECT name, shift
FROM employees
CROSS JOIN shifts
WHERE NOT (name = 'Alice' AND shift = 'Night');

name  │ shift
──────┼────────
Alice │ Morning
Alice │ Evening
Bob   │ Morning
Bob   │ Evening
Bob   │ Night
Carol │ Morning
Carol │ Evening
Carol │ Night

CROSS JOIN vs INNER JOIN

CROSS JOIN                    INNER JOIN
─────────────────────────     ─────────────────────────────
No ON condition needed        Requires ON condition
Every row pairs with every    Only matching rows pair
Result = A rows × B rows      Result ≤ min(A rows, B rows)
Use for: all combinations     Use for: related data lookups

Key Takeaways

  • CROSS JOIN pairs every row from table A with every row from table B
  • Result row count = rows in A × rows in B (can be very large)
  • No ON condition is needed or used
  • Common uses: generating combinations, schedules, pricing grids
  • Always consider result size before cross joining large tables

Leave a Comment

Your email address will not be published. Required fields are marked *