0%
DQDigital Qasas Courses/SQL for Professionals
Sign inAll courses
  • What SQL is, and why professionals learn it
  • Learn faster: pair this course with a free AI assistant
  • SELECT and FROM: your first real query
  • WHERE: keep only the rows you want
  • Combine conditions: AND, OR, IN, BETWEEN, LIKE, NULL
  • ORDER BY, LIMIT, and DISTINCT
  • COUNT, SUM, AVG, MIN, MAX
  • GROUP BY: one number per group
  • HAVING: filter the groups
  • Why tables relate: keys and joins
  • INNER JOIN: matching rows from two tables
  • LEFT JOIN: keep everything, find what is missing
  • Subqueries: a query inside a query
  • CASE: if-and-then inside a query
  • Window functions: a first look
  • Putting it together, and a cheat sheet
  • Practice challenges
Combine tables with joins

Why tables relate: keys and joins

Last updated 14 June 2026

The data is split across tables on purpose. Customer details live once in customers. An order does not repeat the customer name and city. It stores a customer_id that points back to the right customer. That pointer is the link a join follows.

  • A primary key uniquely identifies a row. customers.id is one.
  • A foreign key points at another table's primary key. orders.customer_id points at customers.id.

Storing data once and linking by key is why orders can stay small and why fixing a customer's city is a one-row change. The cost is that to see the name beside an order, you have to join the two tables back together. Run the preview below to see both tables stitched into one result. The next lesson breaks down how.

A join in action. Each order shown with its customer's name.

CREATE TABLE customers (
  id INTEGER PRIMARY KEY,
  name TEXT,
  city TEXT,
  signup_date TEXT
);
INSERT INTO customers VALUES
  (1, 'Aisyah Rahman', 'Kuala Lumpur', '2023-01-12'),
  (2, 'Lim Wei Jie', 'Penang', '2023-02-03'),
  (3, 'Arjun Pillai', 'Johor Bahru', '2023-02-20'),
  (4, 'Nurul Huda', 'Kuala Lumpur', '2023-03-15'),
  (5, 'Tan Mei Ling', 'Ipoh', '2023-05-01'),
  (6, 'Faiz Hassan', 'Penang', '2023-06-10');

CREATE TABLE products (
  id INTEGER PRIMARY KEY,
  name TEXT,
  category TEXT,
  price REAL
);
INSERT INTO products VALUES
  (1, 'Standard License', 'Software', 199.0),
  (2, 'Pro License', 'Software', 499.0),
  (3, 'Onboarding Workshop', 'Service', 1200.0),
  (4, 'Support Plan', 'Service', 300.0),
  (5, 'Data Pack', 'Add-on', 89.0);

CREATE TABLE orders (
  id INTEGER PRIMARY KEY,
  customer_id INTEGER,
  order_date TEXT,
  status TEXT
);
INSERT INTO orders VALUES
  (1001, 1, '2023-03-01', 'paid'),
  (1002, 1, '2023-04-12', 'paid'),
  (1003, 2, '2023-04-15', 'paid'),
  (1004, 3, '2023-05-02', 'refunded'),
  (1005, 4, '2023-05-20', 'paid'),
  (1006, 2, '2023-06-01', 'pending'),
  (1007, 5, '2023-06-18', 'paid');

CREATE TABLE order_items (
  order_id INTEGER,
  product_id INTEGER,
  quantity INTEGER
);
INSERT INTO order_items VALUES
  (1001, 1, 2), (1001, 5, 1),
  (1002, 2, 1),
  (1003, 1, 1), (1003, 4, 1),
  (1004, 3, 1),
  (1005, 2, 2), (1005, 5, 3),
  (1006, 1, 1),
  (1007, 3, 1), (1007, 4, 2);
SELECT orders.id, customers.name, orders.status
FROM orders
JOIN customers ON orders.customer_id = customers.id;

Notice how the result pulls columns from both tables, matched up row by row through customer_id.

A join only finds rows whose keys line up. If an orders row held a customer_id with no matching customers.id, that order would vanish from a plain join. Joins reward clean, consistent keys.

What connects a row in orders to the right row in customers?

  • orders.customer_id pointing at customers.id
  • Both tables being sorted the same way
  • The order in which rows were inserted
The foreign key orders.customer_id stores the customer's primary key. A join follows that pointer to bring the two rows together.
← PreviousHAVING: filter the groupsNext →INNER JOIN: matching rows from two tables