Three real slices of Module 1: the revision notes, the explained Q&A, and the rapid-fire mock. Tap an option on any question — every lesson works like this.
Interviewers do not give you options — they ask a question and listen to how you answer it. So every question in this pack is written the way it is actually asked, and every answer gives you the words to say, the follow-up that comes next, and the thing that loses candidates the round. Try the two below; this is exactly how every lesson behaves.
Q1 Write a query for departments with more than five employees, and tell me why the condition cannot go in WHERE. 📣 Reported in: TCS, Infosys, Accenture, Deloitte analyst rounds
SELECT dept, COUNT(*) AS headcount
FROM employees
WHERE status = 'active' -- row filter, before grouping
GROUP BY dept
HAVING COUNT(*) > 5; -- group filter, after aggregation
Say this: WHERE filters individual rows before the grouping happens, so at that point COUNT(*) does not exist yet — the aggregate is only computed once the rows are grouped. HAVING runs after, which is where an aggregate condition belongs. The execution order is FROM and JOIN, then WHERE, GROUP BY, HAVING, SELECT, ORDER BY, LIMIT.
Follow-up: "Why can't you use a SELECT alias in WHERE, then?" → Same reason — SELECT is evaluated after WHERE. It does work in ORDER BY, which runs later still.
Don’t say: "HAVING is just WHERE for GROUP BY" without the before-versus-after explanation — that sentence is what is actually being graded.
Q2 Salaries in a team are 3, 4, 5, 6 and 50 LPA. What do you report as the typical salary? 📣 Reported in: Deloitte, EY, ZS, analytics firms
Say this: The mean is 13.6 LPA and the median is 5. Not a single person in that team earns anything close to 13.6 — one extreme value has dragged it up — so the median is the honest answer for a typical salary. The rule I follow: median when the distribution is skewed or has outliers, which income, order values and delivery times always are; the mean when totals matter, because mean times count gives the total and median does not.
Follow-up: "So would you ever report the mean here?" → Yes, for total payroll, since that is a sum. I would show both and explain the gap — that gap is itself the finding, because it tells you one person dominates the number.
Don’t say: "The average is 13.6" and stop. Quoting a mean over skewed data without flagging it is the single most common analyst mistake, and this question exists to test for exactly that.
The full pack has revision notes + 125 explained interview questions like these across SQL, Excel, Python & pandas, Statistics and Power BI/Tableau, 62 mock-interview questions, 30 SQL practice problems on one realistic schema with the follow-ups interviewers ask next, and a company-wise module covering what TCS, Infosys, Wipro, Accenture, Capgemini, Deloitte, EY, KPMG, ZS, Mu Sigma, Fractal, LatentView, Amazon, Flipkart and Swiggy actually ask — with every answer written out. No multiple choice anywhere, because no interviewer gives you options.
Every module gives you two study lessons: a 📖 full-notes lesson that teaches the topic in depth, and a ⚡ cheat sheet like this one for quick revision before the Q&A. Here are the first 3 sections of the SQL cheat sheet from Module 1 (SQL).
⚡ Cheat sheet · quick revision before the Q&ASQL is 60% of a data analyst fresher interview. The good news: the questions come from a small set of ideas. Once you can see the order in which a query executes, joins and window functions stop being memorised syntax and become obvious tools.
FROM / JOIN → WHERE → GROUP BY → HAVING → SELECT → DISTINCT → ORDER BY → LIMIT
WHERE filters rows before grouping (cannot see aggregates). HAVING filters groups after aggregation. SELECT aliases exist only from SELECT onward — usable in ORDER BY, not in WHERE (in most databases). Window functions are computed at SELECT time, after WHERE/GROUP BY — so you cannot filter on them directly; wrap in a subquery/CTE.
customers: (1 Asha, Delhi) (2 Ravi, Pune) (3 Meera, Delhi)
orders: (101, cust 1, 500) (102, cust 1, 300) (103, cust 2, 200)
INNER JOIN → 3 rows (Asha ×2, Ravi) -- only customers with orders
LEFT JOIN → 4 rows (… + Meera with NULL order) -- all customers
-- customers with no orders: LEFT JOIN … WHERE o.order_id IS NULL
-- FULL OUTER: both sides; CROSS: 3×3 = 9; SELF JOIN: employees to their managers
Fan-out: a one-to-many join multiplies rows. SUM(amount) after joining orders to order_items double-counts. Aggregate each side first (in a CTE), then join — the single most common real-world SQL bug, and a favourite interview probe.
SELECT city, COUNT(*) AS customers, COUNT(DISTINCT o.customer_id) AS buyers,
SUM(o.amount) AS revenue, ROUND(AVG(o.amount), 2) AS aov
FROM customers c LEFT JOIN orders o ON o.customer_id = c.customer_id
GROUP BY city
HAVING SUM(o.amount) > 1000
ORDER BY revenue DESC;
COUNT(*) rows · COUNT(col) non-NULL · COUNT(DISTINCT col) unique. AVG/SUM ignore NULLs.7 / 2 = 3 in many databases — multiply by 1.0 or cast for percentages.SUM(CASE WHEN status = 'paid' THEN amount ELSE 0 END) — pivots without PIVOT.🔒 5 more sections in the full notes:
+ 2 quick-check interview questions at the end of every study lesson, a ⚡ cheat sheet like this in every module — and a 📖 full-notes lesson that teaches the whole topic in depth before you revise.
After the notes and cheat sheet comes the Q&A lesson — 25 questions asked the way an interviewer asks them, each with a model answer, the follow-up probe and what not to say. Answer aloud first, then open the answer. Here are the first 5 from Module 1.
Q1 What is the execution order of a SQL query? Why does it matter? 🏢 TCS, Infosys, Accenture
Say this: It is not the order you write it in. The engine goes FROM and JOIN first, then WHERE, then GROUP BY, then HAVING, then SELECT, then DISTINCT, then ORDER BY, then LIMIT. That order explains two things people trip on constantly: you cannot use a SELECT alias in WHERE, because SELECT has not run yet — but you can use it in ORDER BY, which runs after. And an aggregate cannot appear in WHERE, because the grouping has not happened; that is what HAVING is for.
Follow-up: "So how do you filter on an alias?" → Wrap the query in a subquery or a CTE and filter in the outer query, or repeat the expression in the WHERE clause.
Don’t say: "SELECT runs first because it is written first" — that is the exact misconception the question is testing.
Q2 WHERE versus HAVING — give me a query using both. 🏢 TCS, Infosys, Wipro, Capgemini — guaranteed
Say this: WHERE filters individual rows before grouping; HAVING filters the groups after aggregation. So a row-level condition goes in WHERE and an aggregate condition goes in HAVING. Putting both in one query makes the difference obvious:
SELECT city, COUNT(*) AS orders, SUM(amount) AS revenue
FROM orders
WHERE status = 'paid' -- row filter, before grouping
GROUP BY city
HAVING SUM(amount) > 100000 -- group filter, after aggregation
ORDER BY revenue DESC;
Follow-up: "Could you put status = 'paid' in HAVING instead?" → Some engines allow it, but it is wrong in spirit and slower — WHERE cuts rows before the expensive grouping, HAVING makes the engine group everything first and then throw work away.
Don’t say: "HAVING is WHERE for GROUP BY" without the before-versus-after distinction — that is the actual answer.
Q3 Customers table has 100 rows, 70 of them have orders. How many rows does a LEFT JOIN return? 🏢 Wipro, Accenture, Deloitte
Say this: It depends on how many orders each customer has, and that is the point of the question. A LEFT JOIN keeps every customer row and matches orders to it — so the 30 customers with no orders appear once each with NULLs, and the 70 with orders appear once per order. If those 70 placed 250 orders between them, the result is 280 rows, not 100. An INNER JOIN would give 250.
The trap this exposes: joining a dimension to a fact table multiplies rows, which is exactly how a report accidentally doubles its revenue. If I only need a count per customer, I aggregate — LEFT JOIN ... GROUP BY customer — and I use COUNT(o.id), not COUNT(*), because COUNT(*) counts the joined row and returns 1 for a customer with no orders.
SELECT c.name, COUNT(o.id) AS orders -- 0 for non-buyers
FROM customers c LEFT JOIN orders o ON o.customer_id = c.id
GROUP BY c.id, c.name;
SELECT c.name FROM customers c -- customers who never ordered
LEFT JOIN orders o ON o.customer_id = c.id
WHERE o.id IS NULL;
Follow-up: "Condition in the ON clause versus the WHERE clause of a LEFT JOIN?" → In ON it filters what gets joined and keeps all left rows; in WHERE it filters after the join and silently turns your LEFT JOIN into an INNER JOIN.
Don’t say: "100 rows" — that is only true if every customer has at most one order.
Q4 Find the second highest salary. Write it two ways. 🏢 THE classic — asked in almost every SQL round
-- 1. subquery
SELECT MAX(salary) FROM employees
WHERE salary < (SELECT MAX(salary) FROM employees);
-- 2. window function
SELECT DISTINCT salary FROM (
SELECT salary, DENSE_RANK() OVER (ORDER BY salary DESC) AS rnk
FROM employees
) t WHERE rnk = 2;
Say the duplicates point unprompted — it is what separates you: if two people share the top salary, LIMIT 1 OFFSET 1 returns that same top figure again, and RANK() skips rank 2 entirely. DENSE_RANK and the MAX-subquery both give the genuinely second-distinct salary.
Follow-up: "Nth highest?" → Change the rank filter to N. "Second highest per department?" → Add PARTITION BY department_id inside the OVER clause.
Don’t say: only the LIMIT/OFFSET version. It is the fastest to type and the easiest to fail on the follow-up.
Q5 On the values 50, 50, 40 — what do RANK, DENSE_RANK and ROW_NUMBER return? 🏢 Accenture, Capgemini, Deloitte, ZS
Say this: RANK gives 1, 1, 3 — ties share the rank and then it skips. DENSE_RANK gives 1, 1, 2 — ties share and nothing is skipped. ROW_NUMBER gives 1, 2, 3 — it always numbers sequentially and breaks the tie arbitrarily, so which of the two 50s gets 1 is not deterministic unless you add a tie-breaker to the ORDER BY.
When I use each: DENSE_RANK for "the Nth distinct value". ROW_NUMBER for deduplication — take row number 1 per group — and for "top N rows regardless of ties". RANK when the competition-style gap is what the business actually wants.
Follow-up: "Deduplicate a table keeping the latest record per customer?" → ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY updated_at DESC) in a CTE, then filter to 1. That is the single most useful window pattern in analytics work.
Don’t say: that RANK and DENSE_RANK are the same — the skip is the whole question.
🔒 20 more explained questions in this lesson — and a 25-question Q&A lesson like this in every tech module, plus the company-wise module with every answer written out.
Every module ends with a mock interview — answer each aloud in 30–60 seconds, then check the key points. First 3 of the 12-question Module 1 mock:
Q1 What is the execution order of a SQL query, and name one thing it explains.
Good answer hits: FROM/JOIN → WHERE → GROUP BY → HAVING → SELECT → DISTINCT → ORDER BY → LIMIT · it explains why a SELECT alias works in ORDER BY but not in WHERE · and why an aggregate cannot go in WHERE.
One-liner: FROM, WHERE, GROUP BY, HAVING, SELECT, ORDER BY, LIMIT — which is why aliases work in ORDER BY and not in WHERE.
Q2 Write the second highest salary query, and tell me what breaks with duplicates.
SELECT MAX(salary) FROM employees
WHERE salary < (SELECT MAX(salary) FROM employees);
Good answer hits: the window version is DENSE_RANK() OVER (ORDER BY salary DESC) filtered to 2 · LIMIT 1 OFFSET 1 returns the same top figure again when two people tie at the top · RANK skips rank 2 after a tie, DENSE_RANK does not.
Q3 On values 50, 50, 40 — what do RANK, DENSE_RANK and ROW_NUMBER give?
Answer: RANK 1, 1, 3 · DENSE_RANK 1, 1, 2 · ROW_NUMBER 1, 2, 3.
Good answer also hits: DENSE_RANK for "Nth distinct value" · ROW_NUMBER for deduplication — PARTITION BY key ORDER BY updated_at DESC, keep row 1 · ROW_NUMBER breaks ties arbitrarily unless you add a tie-breaker to the ORDER BY.
🔒 9 more mock questions in this lesson, and a mock at the end of every module.
Full course
7 modules · 31 lessons · lifetime access
Every module: notes → 25 explained Q&A → mock. Plus the practical round and the company-wise module (TCS, Infosys, Accenture, Capgemini…). 7-day money-back guarantee.