🎯 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:
- Restate the question in your own words
- Clarify grain, ties, NULLs, duplicates, time window
- Shape the output: “one row per city per driver, columns …”
- Build in small CTEs, saying what each produces
- Check against a tiny example and the edge cases
- 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:
- Problem understanding — clarified ambiguity before coding?
- Correctness — right result, including ties and NULLs?
- Edge cases — raised without prompting, or only after hints?
- Code quality — readable CTEs, sensible names, no copy-paste?
- Communication — could they follow your reasoning in real time?
- Efficiency — awareness of scans, indexes, unnecessary self-joins?
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
- LEFT JOIN then WHERE on the right table —
WHERE r.ride_date >= …removes the NULL rows, silently making it an INNER JOIN. Put the filter inON. - *COUNT(col) vs COUNT()** —
COUNT(driver_id)skips NULL drivers;COUNT(*)counts all rows. - WHERE vs HAVING — filtering on
sum(fare)needs HAVING. - Ties — ROW_NUMBER silently drops a tied driver. Ask which behaviour they want.
- Date boundaries —
BETWEEN '2026-10-01' AND '2026-10-31'on a timestamp misses 31 Oct after midnight. - Integer division —
completed / totalreturns 0 in some engines; cast or multiply by1.0. - Duplicates in source — ask if ride_id is unique before summing.
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
| Grain | What one row of the output represents, e.g. one row per city per driver. |
|---|---|
| ROW_NUMBER | Window function giving 1, 2, 3… with no ties; tied rows get arbitrary distinct numbers. |
| RANK | Ties share a rank and leave gaps: 1, 2, 2, 4. |
| DENSE_RANK | Ties share a rank with no gaps: 1, 2, 2, 3. |
| Half-open interval | A date range written as >= start AND < end, which avoids end-of-day boundary bugs. |
| Hint count | How much help the interviewer gave — a key line on the feedback form. |
In two minutes
- Interviewers score understanding, correctness, edge cases, code clarity and communication — not just the final result.
- Restate and clarify before writing: grain, ties, NULLs, duplicates, date boundaries, timezone.
- Say the output shape out loud first — ‘one row per city and driver’ — it prevents half the bugs.
- Build in named CTEs, one idea each, narrating what each step returns.
- Test mentally on a tiny example with a tie, a NULL and an empty group.
- Know the classic traps: LEFT JOIN filtered in WHERE, COUNT(col) vs COUNT(*), WHERE vs HAVING, RANK vs ROW_NUMBER.
- When stuck, say what you're trying and ask a precise question; silence is the only thing that always scores badly.
Test yourself
1. What should come before writing any SQL in the round?
- Restating the question and clarifying ties, NULLs, duplicates and the date range
- Asking for the answer
- Writing the final SELECT
- 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?
- 2
- 3
- 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?
- drivers d LEFT JOIN rides r ON r.driver_id = d.driver_id WHERE r.completed_at >= '2026-10-01'
- rides r LEFT JOIN drivers d ON r.driver_id = d.driver_id
- drivers d INNER JOIN rides r ON r.driver_id = d.driver_id
- 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?
- WHERE sum(fare_inr) > 5000000
- HAVING sum(fare_inr) > 5000000
- ON sum(fare_inr) > 5000000
- 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?
- Stay silent until it comes back
- Say you don't know window functions
- Say what you need (previous month on the same row via LAG), state your assumption about the first row, and ask if that matches
- 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?
- It misses rides on 31 Oct after 00:00:00
- Nothing
- It includes November
- 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.
Start this lesson →