RadhaPublication
HomeInterviewLearning PathsRole TracksMockBooksPricing
Login / Sign UpLog in

© 2026 Radha Publication. All rights reserved.

Shop on AmazonDonateContactPrivacyTerms
SQL questions
EasySQL#417 min readJul 11, 2026

INNER JOIN

practice
joins
learning
Practice modeTest yourself instead of reading straight through

Question: What is an INNER JOIN in SQL?

Answer: An INNER JOIN returns only the rows that match in both tables. If a row in one table has no matching row in the other table, it is dropped from the result. Think of it as the overlap between two lists.

Interview-Ready Answer: I use an INNER JOIN when I want only the rows where the join condition matches on both sides. So if a customer has no orders, that customer will not appear in the result. The key idea is that it keeps the intersection, not the leftovers, and the output can still grow if one row matches many rows on the other side.

🧠 Memory Map
Memory map — visual summary of this topic

What it means

Detailed Explanation: An INNER JOIN combines rows from two tables when the ON condition is true. In plain words: SQL looks for pairs that belong together, builds a combined row, and throws away every non-matching row. The important mental model is that a join is not magic table merging; it is row matching.

  1. Start with the left table and the right table.
  2. Compare rows using the join condition, usually a key like customer_id.
  3. Keep only row pairs where the condition evaluates to true.
  4. Return columns from both sides for those matched pairs.
  5. Drop any row that has no partner.

How the database usually executes it

Under the hood, the database optimizer chooses an execution plan. Common strategies are nested loop join (check many pairs one by one), hash join (build a lookup structure for one side), and merge join (walk through sorted inputs together). You do not usually choose the algorithm directly in SQL, but your indexes, filters, and data sizes influence which one the optimizer picks.

For interview purposes, the key performance idea is simple: a good join on indexed keys can be fast, while a join with no useful index on a huge table can become expensive. In a naive nested loop, cost can look like O(n*m), but a hash join often behaves closer to O(n+m) for the join step, assuming enough memory. Real databases may spill to disk if the hash table is too large, so very large joins can get much slower.

When and why to use it

Use an INNER JOIN when you only care about records that exist in both places: paid orders with payments, employees with departments, products with categories, or users with active subscriptions. It is the default choice when the business question is about matching data, not missing data.

Join typeWhat it keepsTypical use
INNER JOINOnly matchesIntersection
LEFT JOINAll left rowsFind missing right rows
RIGHT JOINAll right rowsMirror of left join
CROSS JOINEvery pairCombinations

Memory hook: picture two guest lists at a party. An INNER JOIN only lets in people whose name appears on both lists.

Important edge cases

Duplicates multiply rows: if one customer has 3 orders, that customer appears 3 times after the join. If both sides have repeated keys, the result can grow quickly. That is not a bug; it is how row matching works.

NULL does not equal NULL: in normal SQL comparisons, NULL means unknown, so NULL = NULL is not true. That means rows with null join keys usually do not match unless you use a dialect-specific null-safe comparison.

Filtering matters: putting conditions in the ON clause changes which rows count as matches. With an INNER JOIN, a condition in WHERE often gives the same final rows as putting it in ON, but not always when outer joins are involved, so be precise from the start.

Logical vs physical order: logically, the join matches rows first and then returns the selected columns. Physically, the optimizer may reorder operations for speed, but the result must still obey SQL rules.

Real-world story

Real-World Example: Imagine a checkout service for an online store. A product analyst wants a report of only paid orders, so the team joins orders to payments using order_id. An INNER JOIN is perfect here because unpaid orders should not appear in the paid-orders report.

What goes wrong when someone misunderstands it? A junior engineer expects the query to show every order and uses an inner join anyway. Suddenly, canceled orders and orders with missing payment records disappear from the dashboard. The symptom is a report that looks too low, support sees customers asking where their purchases went, and logs show fewer rows than expected even though the source tables still contain the data.

The lesson: if the business question is show me the matches, inner join is correct. If the question is show me everything and mark missing matches, you need a left join instead.

SQL
-- Example: INNER JOIN keeps only matching rows from both tables.
-- This script is self-contained and runnable in many SQL databases.

DROP TABLE IF EXISTS orders;
DROP TABLE IF EXISTS customers;

CREATE TABLE customers (
  customer_id INTEGER PRIMARY KEY,
  customer_name VARCHAR(50) NOT NULL
);

CREATE TABLE orders (
  order_id INTEGER PRIMARY KEY,
  customer_id INTEGER,
  amount DECIMAL(10,2) NOT NULL
);

INSERT INTO customers (customer_id, customer_name) VALUES
  (1, 'Ava'),
  (2, 'Ben'),
  (3, 'Chloe');

INSERT INTO orders (order_id, customer_id, amount) VALUES
  (100, 1, 25.00),
  (101, 1, 40.00),
  (102, 2, 15.50),
  (103, NULL, 99.99); -- Edge case: NULL customer_id will not match any customer

-- INNER JOIN returns only the matching customer/order pairs.
SELECT
  c.customer_id,
  c.customer_name,
  o.order_id,
  o.amount
FROM customers AS c
INNER JOIN orders AS o
  ON o.customer_id = c.customer_id
ORDER BY c.customer_id, o.order_id;

-- Failure path demo: Chloe has no orders, so this query returns zero rows.
-- That is expected for INNER JOIN; unmatched left-side rows are dropped.
SELECT
  c.customer_name,
  o.order_id
FROM customers AS c
INNER JOIN orders AS o
  ON o.customer_id = c.customer_id
WHERE c.customer_id = 3;

Follow-up & Tricky Questions

  • What is the difference between INNER JOIN and LEFT JOIN?
    An inner join keeps only matching rows from both tables, while a left join keeps all rows from the left table and fills missing right-side columns with NULL. If you want to find missing relationships, left join is the better tool.
  • Can an inner join return more rows than either input table?
    Yes. If one row matches many rows on the other side, the result multiplies, so the output can be larger than both tables.
  • Does the join condition have to use equality?
    No. An inner join can use any boolean condition, such as ranges or multiple predicates, as long as the condition tells SQL which pairs count as matches.
  • What happens if the join key is NULL?
    A normal equality match will not join NULL to anything, including another NULL, because NULL means unknown. That is a very common source of missing rows.
  • Is the order of tables in an inner join important?
    Logically, an inner join is symmetric: the same matching pairs are found either way. The optimizer may choose different physical plans, but the final matched set is the same.
  • Does INNER JOIN remove duplicates?
    No. It can actually create more duplicates if the join keys are repeated on either side. Deduplication would require DISTINCT or a different query shape.
  • Is missing the ON clause an inner join?
    Usually no; it becomes a cross join or a syntax error depending on the database and syntax used. This is one of the fastest ways to accidentally create a huge result set.

Tricky / gotcha questions:

  • If two tables have the same column name, does SQL know which one to use?
    Not always. You should qualify the column with a table alias, like c.customer_id, to avoid ambiguity and to make your query readable.
  • If I move a filter from ON to WHERE, is it always the same for inner joins?
    Often the final result is the same for a pure inner join, but it is a risky habit because the meaning changes with outer joins. Good interview answers show that you understand the difference, not just the syntax.
  • Can an inner join match rows on only part of a composite key?
    Yes, but that is usually a data-model smell. If the real relationship uses two columns and you join on only one, you can create accidental duplicates and wrong totals.

Wrap-up

Common Mistakes:

  • Using INNER JOIN when you actually need missing rows too. Correction: switch to LEFT JOIN if you need every left-side row.
  • Forgetting that duplicate keys multiply rows. Correction: check cardinality before assuming one-to-one matching.
  • Assuming NULL values will match. Correction: remember that NULL is unknown, so equality usually fails.
  • Joining on the wrong column or incomplete key. Correction: verify the real business key, not just a column with the same name.

Memory Hook: Think of an inner join as the intersection of two guest lists: only people invited on both lists get in.

Cheat Sheet:

  • Inner join = keep only matching rows.
  • Join condition belongs in ON.
  • Duplicates can multiply the result.
  • NULL does not match with =.
  • Use it for intersection-style questions.
  • Use indexes on join keys when data is large.

Practice Tasks:

  • Join employees to departments and return only employees who have a department.
  • Add one employee with a missing department and confirm that inner join drops them.
  • Create a many-to-many example and count how the result multiplies.
Previous
Back to Questions←→to navigate
Next

Recommended Resources

Recommended Book

Cracking the Coding Interview

189 Programming Questions and Solutions

Recommended Book

Cracking the Coding Interview

189 Programming Questions and Solutions

-- Example: INNER JOIN keeps only matching rows from both tables. -- This script is self-contained and runnable in many SQL databases. DROP TABLE IF EXISTS orders; DROP TABLE IF EXISTS customers; CREATE TABLE customers ( customer_id INTEGER PRIMARY KEY, customer_name VARCHAR(50) NOT NULL ); CREATE TABLE orders ( order_id INTEGER PRIMARY KEY, customer_id INTEGER, amount DECIMAL(10,2) NOT NULL ); INSERT INTO customers (customer_id, customer_name) VALUES (1, 'Ava'), (2, 'Ben'), (3, 'Chloe'); INSERT INTO orders (order_id, customer_id, amount) VALUES (100, 1, 25.00), (101, 1, 40.00), (102, 2, 15.50), (103, NULL, 99.99); -- Edge case: NULL customer_id will not match any customer -- INNER JOIN returns only the matching customer/order pairs. SELECT c.customer_id, c.customer_name, o.order_id, o.amount FROM customers AS c INNER JOIN orders AS o ON o.customer_id = c.customer_id ORDER BY c.customer_id, o.order_id; -- Failure path demo: Chloe has no orders, so this query returns zero rows. -- That is expected for INNER JOIN; unmatched left-side rows are dropped. SELECT c.customer_name, o.order_id FROM customers AS c INNER JOIN orders AS o ON o.customer_id = c.customer_id WHERE c.customer_id = 3;