◐ ai-teacher

🎯 Interview & Career · Chapter 2

The SQL round: how to think out loud

The SQL round isn't graded on the query. It's graded on the evidence the interviewer can write down — and they can only write down what you say.

Study this lesson free in the app →

The basics

The SQL round is a live interview where you're given a schema and a business question — “top 3 drivers by earnings in each city last month” — and write a query in a shared editor while the interviewer watches.

Why thinking out loud matters: the interviewer has to fill in a feedback form afterwards: did they understand the problem? handle edge cases? write clean, correct SQL? communicate? A correct query typed in silence gives them almost nothing to write. A slightly slower query with clear reasoning gives them a page.

The mental model — six moves, every time:

  1. Restate the question in your own words
  2. Clarify grain, ties, NULLs, duplicates, time window
  3. Shape the output: “one row per city per driver, columns …”
  4. Build in small CTEs, saying what each produces
  5. Check against a tiny example and the edge cases
  6. Extend: performance, indexes, alternatives

Words to know: grain, tie-breaking, ROW_NUMBER / RANK / DENSE_RANK, CTE, edge case.

Explained

Two candidates, same question, same correct query.

Candidate A types for six minutes in silence and says “done”.

Candidate B says: “So, per city, I want the three drivers who earned most in October. Quick check — if two drivers tie for third, should both appear? And earnings means completed rides only, excluding cancelled?” — then builds it in three CTEs, explaining each.

A gets “correct, little signal”. B gets “strong hire”. Same SQL. Different evidence.

The tailor's fitting

A good tailor in Police Bazaar doesn't start cutting the moment you say “a shirt”.

He asks: Formal or casual? Slim or regular? Full sleeve? He measures. He says back: “So, slim fit, full sleeve, two pockets.” Only then does he cut — and at the fitting he checks the sleeves while you stand there.

A tailor who silently cuts a perfect shirt is fine. One who cuts the wrong shirt fast is a disaster. Clarify, confirm the shape, cut, then check the fit — that's the SQL round.

The six moves

Clarifying takes 60–90 seconds. It's the highest-return minute of the round.

The query, built the way you'd narrate it

-- “First, completed rides in October, IST.”
WITH oct_rides AS (
  SELECT city, driver_id, fare_inr
  FROM rides
  WHERE status = 'completed'
    AND completed_at >= '2026-10-01' AND completed_at < '2026-11-01'
),
-- “Then one row per city and driver with total earnings.”
earnings AS (
  SELECT city, driver_id, sum(fare_inr) AS earnings_inr
  FROM oct_rides
  GROUP BY city, driver_id
),
-- “Rank within each city. You said ties should both appear, so DENSE_RANK.”
ranked AS (
  SELECT *, DENSE_RANK() OVER (PARTITION BY city ORDER BY earnings_inr DESC) AS rnk
  FROM earnings
)
SELECT city, driver_id, earnings_inr, rnk
FROM ranked
WHERE rnk <= 3
ORDER BY city, rnk;

Notice the half-open date range (< '2026-11-01') — say why: it includes all of 31 October regardless of time.

What the interviewer's form actually says

Most companies score something like:

And the line that matters most is hints needed. Getting there after one hint is fine. Needing the interviewer to point at every bug is a no. Raising the bug yourself — “wait, this LEFT JOIN plus WHERE will drop drivers with no rides” — is one of the strongest signals in the round.

The traps they plant on purpose

When you get stuck — what to say

You need each driver's earnings vs the previous month and you blank on the syntax.

Bad: 40 seconds of silence, then “sorry, I don't remember”.

Good: “I want the previous month's value on the same row — that's a window function, LAG partitioned by driver ordered by month. I'm not 100% sure of the default for the first row; I believe it returns NULL, so I'll coalesce it to 0 and treat that as a new driver. Does that match what you want for new drivers?”

You've shown you know the concept, the edge case and the business question — even if the syntax is slightly off. Interviewers forgive syntax. They don't forgive silence.

Restate, clarify, shape, build, check, extend — out loud.

The interviewer can only grade what they hear. Ties, NULLs and the LEFT JOIN trap: raise them before they do.

Words to know

GrainWhat one row of the output represents, e.g. one row per city per driver.
ROW_NUMBERWindow function giving 1, 2, 3… with no ties; tied rows get arbitrary distinct numbers.
RANKTies share a rank and leave gaps: 1, 2, 2, 4.
DENSE_RANKTies share a rank with no gaps: 1, 2, 2, 3.
Half-open intervalA date range written as >= start AND < end, which avoids end-of-day boundary bugs.
Hint countHow much help the interviewer gave — a key line on the feedback form.

In two minutes

Test yourself

1. What should come before writing any SQL in the round?

  1. Restating the question and clarifying ties, NULLs, duplicates and the date range
  2. Asking for the answer
  3. Writing the final SELECT
  4. Discussing indexes
Show the answer

Restating the question and clarifying ties, NULLs, duplicates and the date range — Clarifying first prevents solving the wrong problem and gives the interviewer evidence of problem understanding.

2. Earnings in Shillong: D1 42k, D2 39.5k, D3 39.5k, D4 37k. With DENSE_RANK() and rnk <= 3, how many drivers are returned?

  1. 2
  2. 3
  3. 4
  4. 1
Show the answer

4 — DENSE_RANK gives 1, 2, 2, 3 — all four have rank ≤ 3. RANK would give 1, 2, 2, 4 (three rows); ROW_NUMBER exactly three.

3. You want all drivers including those with zero October rides. Which is correct?

  1. drivers d LEFT JOIN rides r ON r.driver_id = d.driver_id WHERE r.completed_at >= '2026-10-01'
  2. rides r LEFT JOIN drivers d ON r.driver_id = d.driver_id
  3. drivers d INNER JOIN rides r ON r.driver_id = d.driver_id
  4. drivers d LEFT JOIN rides r ON r.driver_id = d.driver_id AND r.completed_at >= '2026-10-01' AND r.completed_at < '2026-11-01'
Show the answer

drivers d LEFT JOIN rides r ON r.driver_id = d.driver_id AND r.completed_at >= '2026-10-01' AND r.completed_at < '2026-11-01' — Filters on the right table belong in ON. In WHERE, they discard the NULL-extended rows for drivers with no rides, turning it into an inner join.

4. Filter to cities whose total October earnings exceed ₹50 lakh. Which clause?

  1. WHERE sum(fare_inr) > 5000000
  2. HAVING sum(fare_inr) > 5000000
  3. ON sum(fare_inr) > 5000000
  4. QUALIFY sum(fare_inr) > 5000000
Show the answer

HAVING sum(fare_inr) > 5000000 — WHERE filters rows before grouping; aggregate conditions need HAVING after GROUP BY.

5. You're stuck on the exact syntax of LAG. Best response?

  1. Stay silent until it comes back
  2. Say you don't know window functions
  3. Say what you need (previous month on the same row via LAG), state your assumption about the first row, and ask if that matches
  4. Switch to a different problem
Show the answer

Say what you need (previous month on the same row via LAG), state your assumption about the first row, and ask if that matches — It shows the concept, the edge case and the business question. Interviewers routinely forgive syntax; they can't score silence.

6. Trap: WHERE completed_at BETWEEN '2026-10-01' AND '2026-10-31' on a timestamp column. What's wrong?

  1. It misses rides on 31 Oct after 00:00:00
  2. Nothing
  3. It includes November
  4. BETWEEN doesn't work on timestamps
Show the answer

It misses rides on 31 Oct after 00:00:00 — '2026-10-31' means midnight at the start of 31 Oct. Use >= '2026-10-01' AND < '2026-11-01'.

There are 8 questions, 3 puzzles and 5 recall cards for this lesson in the app — the recall cards come back on later days, just before you would forget.

Learn it so it stays. Read it, test yourself, then recall it on two different days. The app schedules that for you, free.

Start this lesson →