Cross-reference data from two tables with INNER JOIN, readable aliases and a precise join condition.
Open this lesson in KodokonA real database never stores everything in a single table: customers on one side, their orders on the other. To practise this module, open sqliteonline.com in your browser (no installation needed) or launch the sqlite3 tool in a terminal. First paste the script below: it creates the two tables used in this lesson.
CREATE TABLE customers (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
city TEXT
);
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
customer_id INTEGER NOT NULL,
amount REAL NOT NULL,
ordered_at TEXT NOT NULL
);
INSERT INTO customers (id, name, city) VALUES
(1, 'Alice', 'Lyon'),
(2, 'Karim', 'Paris'),
(3, 'Mina', 'Nantes');
INSERT INTO orders
(id, customer_id, amount, ordered_at)
VALUES
(1, 1, 49.90, '2026-06-01'),
(2, 1, 15.00, '2026-06-12'),
(3, 2, 120.50, '2026-06-15');INNER JOIN assembles two tables row by row according to a matching condition written after ON. Here, each order is linked to the customer whose id equals its customer_id. Rows without a match are dropped from the result: Mina, who ordered nothing, does not appear.
SELECT customers.name, orders.amount
FROM orders
INNER JOIN customers
ON customers.id = orders.customer_id;Repeating the full table names quickly becomes unreadable. An alias declared with AS renames the table for the duration of the query. Always prefix ambiguous columns: id exists in both tables, so write c.id or o.id, never id on its own.
SELECT c.name, o.amount, o.ordered_at
FROM orders AS o
INNER JOIN customers AS c
ON c.id = o.customer_id
WHERE o.amount > 20
ORDER BY o.amount DESC;