SQL Interview Questions
SQL Interview Questions
College Placements
A Focused Guide to the SQL Questions That Actually Get Asked at TCS,
Infosys, Wipro, Accenture, Capgemini, Cognizant, and Other Mass-Recruiter
& Product Companies
2026
Contents
How to Use This Guide 3
1
Q25. Subquery — Employees Earning More Than the Average Salary . . . . 25
Q26. EXISTS — Customers Who Have Placed at Least One Order . . . . . . 26
Q27. NOT EXISTS — Customers Who Never Placed an Order . . . . . . . . 27
Q28. Correlated Subquery — Employees Earning More Than Their Depart-
ment’s Average . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
Q29. Simple CTE — Rewrite a Subquery Using WITH . . . . . . . . . . . . 30
Q30. Date Functions — Orders Placed in the Last 30 Days . . . . . . . . . . 31
Q31. Find Duplicate Records in a Table . . . . . . . . . . . . . . . . . . . . 31
Q32. Delete Duplicate Rows (Query Only) . . . . . . . . . . . . . . . . . . . 32
Q33. Odd and Even Numbered Rows . . . . . . . . . . . . . . . . . . . . . 34
Q34. Second Highest Salary . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Q35. Third Highest Salary . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
Q36. Nth Highest Salary . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Q37. Highest Salary in Each Department . . . . . . . . . . . . . . . . . . . 38
Q38. Employees Earning More Than Their Managers . . . . . . . . . . . . . 39
Q39. Top 3 Salaries (Overall) . . . . . . . . . . . . . . . . . . . . . . . . . . 40
Q40. Running Total of Salaries (Simple Version) . . . . . . . . . . . . . . . 41
Q41. Employees Who Joined in the Last N Months (Combining WHERE, Date
Functions, and ORDER BY) . . . . . . . . . . . . . . . . . . . . . . . . 42
2
How to Use This Guide
This guide does not try to cover all of SQL. It covers exactly one thing: the SQL ques-
tions that get repeated, year after year, in campus placement interviews at mass-
recruiter IT services companies (TCS, Infosys, Wipro, Accenture, Capgemini, Cog-
nizant, Deloitte, HCL, Tech Mahindra, LTIMindtree, IBM, PwC, EY, Zensar, Persistent,
Hexaware, Nagarro, Publicis Sapient) and in the basic SQL rounds of product-based
companies.
What you will find here
• 41 questions, arranged from easiest to hardest, covering every topic that shows
up again and again in interview experiences shared by students from Tier-3 col-
leges.
• For every question: the question itself, its difficulty, the concepts it tests, a ta-
ble schema, sample data, a working SQL solution, a line-by-line explanation, the
expected output, common mistakes candidates make, and similar questions in-
terviewers ask as follow-ups.
• A revision section at the end with 20 interview tips, a query-writing strategy,
SQL execution order, comparison tables (GROUP BY vs HAVING, WHERE vs
HAVING), a JOIN cheat sheet, an aggregate function cheat sheet, common mis-
takes, and a one-page revision sheet.
What you will not find here
Recursive CTEs, complex window function problems, PIVOT/UNPIVOT, dynamic SQL,
stored procedures, triggers, views, transactions, and hard LeetCode-style SQL. These
are rarely, if ever, asked to freshers in a first or second round SQL interview, and
including them would only distract you from what actually gets asked.
How to practice with this guide
1. Go through the questions in order — they are sequenced from easiest to hardest.
2. For each question, read only the question and try to write the query yourself
before looking at the solution.
3. Compare your query with the given solution and read the explanation.
4. Pay close attention to the “Common Interview Mistakes” box — this is usually
exactly where candidates lose marks.
5. Once you’re comfortable, revise using the one-page revision sheet before your
interview.
All examples use standard SQL (MySQL/SQL Server style syntax, with notes wherever
a database-specific function is used, such as DATE_SUB in MySQL vs DATEADD in SQL
Server).
3
Section A: Easy Questions
These are almost always the first few questions in any written SQL test or the opening
questions of a technical interview. They test whether you know the basic syntax.
Column Type
emp_id INT (PK)
emp_name VARCHAR(50)
department VARCHAR(30)
salary INT
join_date DATE
SQL Solution
SELECT * FROM Employee;
Line-by-Line Explanation
• SELECT * chooses every column in the table.
• FROM Employee tells the database which table to read from.
• The semicolon ends the statement.
Expected Output
All 4 rows shown above, with all 5 columns, exactly as stored.
Common Interview Mistakes
• Using SELECT * in real production code (interviewers often ask “is this a good
practice?” — the correct answer is no, because it fetches unnecessary columns
and hurts performance).
• Forgetting the semicolon (usually not an error, but good habit to mention).
Similar Questions Interviewers Ask
• Why is SELECT * considered bad practice?
4
• How do you select all columns except one?
Line-by-Line Explanation
• Only emp_name, department, and salary are listed after SELECT, so only these
three columns are returned.
• Column order in the output follows the order you list them in, not the table’s
original order.
Expected Output
5
SELECT emp_name, salary
FROM Employee
WHERE department = 'IT';
Line-by-Line Explanation
• WHERE department = 'IT' filters rows so only employees whose department is
IT are returned.
• The WHERE clause runs before columns are selected, so it can filter on columns
that aren’t even in the SELECT list.
Expected Output
emp_name salary
Aman 45000
Kabir 52000
Line-by-Line Explanation
• DISTINCT removes duplicate values from the result set.
• Applied here on a single column, it returns each department name only once, no
matter how many employees belong to it.
Expected Output
6
department
IT
HR
Finance
Line-by-Line Explanation
• ORDER BY salary DESC sorts the result set by the salary column from highest to
lowest.
• If DESC were removed, the default sort order is ascending (ASC).
Expected Output
emp_name salary
Kabir 52000
Aman 45000
Sneha 41000
Riya 38000
7
• Assuming ORDER BY runs before WHERE — it actually runs almost last, after filtering
and grouping.
• Forgetting that without ORDER BY, SQL does not guarantee any particular row
order.
Similar Questions Interviewers Ask
• How do you sort by multiple columns?
• How do you sort in descending order and then break ties using another column?
-- SQL Server
SELECT TOP 2 emp_name, salary
FROM Employee
ORDER BY salary DESC;
Line-by-Line Explanation
• The rows are first sorted by salary in descending order.
• LIMIT 2 (or TOP 2 in SQL Server) then keeps only the first 2 rows of that sorted
result — effectively the two highest-paid employees.
Expected Output
emp_name salary
Kabir 52000
Aman 45000
8
Similar Questions Interviewers Ask
• How would you get the top 3 salaries? (covered later as its own question)
• What is the syntax difference between MySQL’s LIMIT and SQL Server’s TOP?
Line-by-Line Explanation
• LIKE 'A%' matches any name that starts with the letter “A”.
• % is a wildcard for zero or more characters; _ (not used here) matches exactly
one character.
Expected Output
emp_name
Aman
9
SELECT emp_name, department
FROM Employee
WHERE department IN ('IT', 'HR');
Line-by-Line Explanation
• IN ('IT', 'HR') checks if department matches any value in the given list.
• This is a shorter, more readable way of writing department = 'IT' OR department
= 'HR'.
Expected Output
emp_name department
Aman IT
Riya HR
Kabir IT
Line-by-Line Explanation
• BETWEEN 40000 AND 50000 keeps rows where salary is greater than or equal to
40000 and less than or equal to 50000.
• BETWEEN is always inclusive of both boundary values.
10
Expected Output
emp_name salary
Aman 45000
Sneha 41000
Column Type
emp_id INT (PK)
emp_name VARCHAR(50)
manager_id INT (nullable)
SQL Solution
SELECT emp_name
FROM Employee2
WHERE manager_id IS NULL;
Line-by-Line Explanation
11
• IS NULL is the only correct way to check for missing values; = NULL never works
because NULL means “unknown” and is not equal to anything, not even itself.
• Here it finds the employee who has no manager, i.e., the top of the hierarchy.
Expected Output
emp_name
Kabir
Line-by-Line Explanation
• COUNT(*) counts every row in the table, including rows that contain NULLs in
some columns.
• AS total_employees renames the output column so it’s readable.
Expected Output
total_employees
4
12
Similar Questions Interviewers Ask
• What is the difference between COUNT(*), COUNT(1), and COUNT(column_name)?
• How do you count employees per department? (covered later)
Line-by-Line Explanation
• SUM(salary) adds up the salary value from every row.
• NULL values are automatically ignored by SUM, so they don’t need special han-
dling.
Expected Output
total_salary
176000
13
SELECT AVG(salary) AS avg_salary
FROM Employee;
Line-by-Line Explanation
• AVG(salary) computes the mean of all salary values, ignoring NULLs both in
the sum and in the count of rows used for division.
Expected Output
avg_salary
44000
Line-by-Line Explanation
• MIN(salary) scans all rows and returns the smallest salary value.
• MIN works on numbers, dates, and even strings (alphabetical order).
Expected Output
min_salary
38000
14
• Trying to also fetch the employee’s name in the same SELECT without GROUP BY
or a subquery, e.g. SELECT emp_name, MIN(salary) FROM Employee — this is
invalid/misleading in strict SQL modes because emp_name isn’t aggregated or
grouped.
Similar Questions Interviewers Ask
• How do you find the employee(s) who earn the minimum salary? (needs a sub-
query: WHERE salary = (SELECT MIN(salary) FROM Employee))
• Can MIN be used on a date column?
Line-by-Line Explanation
• MAX(salary) returns the largest value found in the salary column across all rows.
Expected Output
max_salary
52000
15
Same Employee table.
SQL Solution
SELECT department, SUM(salary) AS dept_total_salary
FROM Employee
GROUP BY department;
Line-by-Line Explanation
• GROUP BY department collects all rows with the same department value into one
group.
• SUM(salary) is then calculated separately for each group instead of for the whole
table.
Expected Output
department dept_total_salary
IT 97000
HR 38000
Finance 41000
Line-by-Line Explanation
16
• Rows are grouped by department and SUM(salary) is computed per group, ex-
actly as in Q16.
• HAVING SUM(salary) > 40000 then removes any group whose total salary is 40000
or less — this filtering happens after grouping, unlike WHERE.
Expected Output
department dept_total_salary
IT 97000
Finance 41000
Line-by-Line Explanation
• Employees are grouped by department.
• COUNT(*) then counts how many rows (employees) fall into each department
group.
Expected Output
department num_employees
IT 2
17
department num_employees
HR 1
Finance 1
Line-by-Line Explanation
• CASE WHEN condition1 THEN result1 WHEN condition2 THEN result2 ELSE
default END works like an if-else chain, evaluated top to bottom for each row.
• For each employee, the first matching condition decides the label; if none match,
ELSE 'Low' is used.
• AS salary_band names this new computed column.
Expected Output
18
emp_name salary salary_band
Kabir 52000 High
Sneha 41000 Medium
19
Section B: Medium Questions
This is the section that decides most interviews. JOINs, subqueries, and the “Nth
highest salary” family of questions are asked at almost every single company on the
list.
dept_id dept_name
10 IT
20 HR
30 Finance
SQL Solution
SELECT e.emp_name, d.dept_name
FROM Employee e
INNER JOIN Department d
ON e.dept_id = d.dept_id;
Line-by-Line Explanation
• INNER JOIN Department d ON e.dept_id = d.dept_id matches rows from Em-
ployee to rows in Department wherever the dept_id values are equal.
• Only rows that have a match in both tables are returned; Sneha (NULL dept_id)
and Finance (no employees) are both dropped.
• e and d are table aliases used to keep column references short.
Expected Output
emp_name dept_name
Aman IT
Riya HR
Kabir IT
20
Common Interview Mistakes
• Forgetting the ON condition, which produces a cross join (every row combined
with every row) instead of a proper match.
• Assuming INNER JOIN returns all rows from the left table like LEFT JOIN does.
Similar Questions Interviewers Ask
• What’s the difference between INNER JOIN and LEFT JOIN?
• Can you join more than two tables? (yes, covered later)
Q21. LEFT JOIN — Keep All Rows From the Left Table
Difficulty: Medium Concepts Tested: LEFT JOIN
Table Schema
Same Employee and Department tables as Q20.
SQL Solution
SELECT e.emp_name, d.dept_name
FROM Employee e
LEFT JOIN Department d
ON e.dept_id = d.dept_id;
Line-by-Line Explanation
• LEFT JOIN keeps every row from the left table (Employee), regardless of whether
a match is found in Department.
• Where there is no match (Sneha’s dept_id is NULL), the columns coming from
the right table (dept_name) are filled with NULL.
Expected Output
emp_name dept_name
Aman IT
Riya HR
Kabir IT
Sneha NULL
21
• How do you find rows that exist only in the left table and not in the right table?
(LEFT JOIN ... WHERE right_table.key IS NULL — this is exactly the pattern
used for “customers with no orders”)
• What is a RIGHT JOIN, and can it always be rewritten as a LEFT JOIN? (yes, by
swapping table order)
customer_id customer_name
1 Ravi
2 Meena
3 Farhan
SQL Solution
SELECT c.customer_name
FROM Customers c
LEFT JOIN Orders o
ON c.customer_id = o.customer_id
WHERE o.order_id IS NULL;
Line-by-Line Explanation
• LEFT JOIN Orders keeps every customer, matching them to their orders where
possible.
• Customers with no orders end up with NULL in every column that came from
Orders, including order_id.
• WHERE o.order_id IS NULL keeps only those customers — i.e., customers who
never placed a single order.
Expected Output
customer_name
Meena
22
customer_name
Farhan
SQL Solution
SELECT e.emp_name AS employee, m.emp_name AS manager
FROM Employee e
LEFT JOIN Employee m
ON e.manager_id = m.emp_id;
Line-by-Line Explanation
• The Employee table is joined to itself, so it needs two different aliases (e for the
employee row, m for the manager row) to tell the two “copies” apart.
• ON e.manager_id = m.emp_id matches each employee’s manager_id to the emp_id
of their manager in the second copy of the table.
• LEFT JOIN is used so that Kabir (who has no manager) still appears, with manager
shown as NULL.
23
Expected Output
employee manager
Aman Kabir
Riya Kabir
Kabir NULL
Sneha Aman
dept_id dept_name
10 IT
20 HR
SQL Solution
24
SELECT e.emp_name, d.dept_name, p.project_name
FROM Employee e
INNER JOIN Department d ON e.dept_id = d.dept_id
INNER JOIN Project p ON e.emp_id = p.emp_id;
Line-by-Line Explanation
• The query starts from Employee and joins to Department using dept_id, bringing
in the department name.
• It then joins that intermediate result to Project using emp_id, bringing in the
project each employee works on.
• Each JOIN is evaluated in order, and the alias from an earlier join can be reused
in a later one.
Expected Output
Line-by-Line Explanation
25
• The inner query SELECT AVG(salary) FROM Employee runs first and produces a
single number — the average salary (44000, using the Q1 data).
• The outer query then compares every employee’s salary against that single
value and keeps only the rows where it’s greater.
• Because the inner query returns exactly one value, it can be used directly after
a comparison operator like >.
Expected Output
emp_name salary
Aman 45000
Kabir 52000
Line-by-Line Explanation
• The subquery is run once per customer row from the outer query — this is what
makes it a “correlated” subquery, because it refers back to c.customer_id.
26
• EXISTS only checks whether the subquery returns any row at all; it doesn’t mat-
ter what the row’s actual values are, which is why SELECT 1 is commonly used
instead of listing real columns.
• If at least one order matches that customer’s ID, the customer is included in the
result.
Expected Output
customer_name
Ravi
Line-by-Line Explanation
• This is the exact opposite of Q26: for every customer, the subquery checks if any
order row matches their customer_id.
• NOT EXISTS keeps the customer only when zero matching order rows are found.
• This is generally considered the safest way to answer “which customers never
ordered”, safer than NOT IN.
27
Expected Output
customer_name
Meena
Farhan
Line-by-Line Explanation
• The inner query calculates the average salary, but only for rows in e2 where
the department matches the current outer row’s department ([Link] =
[Link]) — this correlation is what makes it re-run for every employee.
• The outer query then keeps the employee only if their own salary is above that
department-specific average.
28
• This is a very common way interviewers test whether a candidate actually un-
derstands correlated subqueries versus plain subqueries.
Expected Output
Using the Q1 sample data (IT average = 48500, HR average = 38000, Finance average
= 41000):
29
Q29. Simple CTE — Rewrite a Subquery Using WITH
Difficulty: Medium Concepts Tested: Simple CTE (Common Table Expression)
Table Schema
Same Employee table as Q1.
SQL Solution
WITH DeptAvg AS (
SELECT department, AVG(salary) AS avg_salary
FROM Employee
GROUP BY department
)
SELECT e.emp_name, [Link], [Link], d.avg_salary
FROM Employee e
JOIN DeptAvg d
ON [Link] = [Link]
WHERE [Link] > d.avg_salary;
Line-by-Line Explanation
• WITH DeptAvg AS (...) defines a temporary, named result set (a CTE) that exists
only for the duration of this query — here it calculates the average salary per
department.
• The main query then simply joins Employee to DeptAvg on department, which
reads much more clearly than nesting the same logic inside a WHERE clause.
• WHERE [Link] > d.avg_salary keeps only employees whose salary beats their
department’s average — the same result as Q28’s correlated subquery, but writ-
ten differently.
Expected Output
30
Q30. Date Functions — Orders Placed in the Last 30 Days
Difficulty: Medium Concepts Tested: Date functions, CURDATE/GETDATE,
DATE_SUB/DATEADD
Table Schema
Same Orders table as Q22 (order_id, customer_id, order_date).
SQL Solution
-- MySQL
SELECT *
FROM Orders
WHERE order_date >= CURDATE() - INTERVAL 30 DAY;
-- SQL Server
SELECT *
FROM Orders
WHERE order_date >= DATEADD(DAY, -30, GETDATE());
Line-by-Line Explanation
• CURDATE() (MySQL) or GETDATE() (SQL Server) returns today’s date.
• Subtracting 30 days from today gives the cutoff date exactly one month back.
• The WHERE clause then keeps only orders whose order_date is on or after that
cutoff — i.e., placed within the last 30 days.
Expected Output
Depends on the current date and the data, but structurally it’s a subset of the Orders
table containing only recent rows, with all original columns intact.
Common Interview Mistakes
• Hardcoding a specific date instead of using the database’s “today” function,
which breaks the query the next time it’s run.
• Mixing up date function names across databases — MySQL uses DATE_SUB()/CURDATE(),
SQL Server uses DATEADD()/GETDATE(), and interviewers often just want to see
that you know one syntax well and are aware the other exists.
Similar Questions Interviewers Ask
• How do you extract just the year or month from a date column? (YEAR(order_date),
MONTH(order_date))
• How do you find orders placed in a specific month, regardless of year?
31
Student(student_id, student_name, email)
SQL Solution
SELECT email, COUNT(*) AS occurrences
FROM Student
GROUP BY email
HAVING COUNT(*) > 1;
Line-by-Line Explanation
• Rows are grouped by email, since that’s the column being checked for duplica-
tion.
• COUNT(*) counts how many rows share each email.
• HAVING COUNT(*) > 1 keeps only the groups (emails) that appear more than once
— i.e., actual duplicates.
Expected Output
email occurrences
priya@[Link] 2
32
Same Student table as Q31.
SQL Solution
DELETE FROM Student
WHERE student_id NOT IN (
SELECT MIN(student_id)
FROM Student
GROUP BY email
);
Line-by-Line Explanation
• The subquery groups all rows by email and picks the smallest student_id in each
group — effectively choosing one row to “keep” per duplicate email.
• The outer DELETE then removes every row whose student_id is not one of those
kept IDs, leaving exactly one row per unique email.
• This pattern (keep the MIN or MAX id, delete the rest) is the standard, most com-
monly expected answer to this classic question.
Expected Output
After running this query, the Student table would contain only:
33
Q33. Odd and Even Numbered Rows
Difficulty: Medium Concepts Tested: MOD, row numbering logic
Table Schema
Same Employee table as Q1, assume emp_id values are 1, 2, 3, 4.
SQL Solution
-- Odd-numbered rows (by emp_id)
SELECT * FROM Employee WHERE emp_id % 2 = 1;
Line-by-Line Explanation
• % is the modulo operator — emp_id % 2 gives the remainder after dividing emp_id
by 2.
• A remainder of 1 means the emp_id is odd; a remainder of 0 means it’s even.
• This is commonly asked using emp_id, but interviewers sometimes really mean
the row position in the result set, which needs ROW_NUMBER() — worth clarifying
out loud in the interview which one is meant.
Expected Output
Odd query returns emp_id 1 and 3 (Aman, Kabir); even query returns emp_id 2 and 4
(Riya, Sneha).
Common Interview Mistakes
• Assuming emp_id is always sequential with no gaps — if rows have been deleted,
emp_id % 2 no longer matches the actual row position.
• Confusing this with ROW_NUMBER() % 2, which is what’s needed if the interviewer
means “every alternate row” rather than “rows with odd/even IDs”.
Similar Questions Interviewers Ask
• How would you solve this if emp_id had gaps and you truly needed alternate rows
by position? (ROW_NUMBER() — mentioned as an advanced follow-up, not expected
in detail at fresher level)
• What does the % operator do in SQL versus in general programming languages?
34
-- Method 1: Subquery with MAX
SELECT MAX(salary) AS second_highest_salary
FROM Employee
WHERE salary < (SELECT MAX(salary) FROM Employee);
second_highest_salary
45000
35
Q35. Third Highest Salary
Difficulty: Medium Concepts Tested: Subquery nesting, LIMIT/OFFSET
Table Schema
Same Employee table as Q1.
SQL Solution
-- Method 1: Nested subquery
SELECT MIN(salary) AS third_highest_salary
FROM (
SELECT DISTINCT salary
FROM Employee
ORDER BY salary DESC
LIMIT 3
) AS top3;
-- Method 2: OFFSET
SELECT DISTINCT salary
FROM Employee
ORDER BY salary DESC
LIMIT 1 OFFSET 2;
third_highest_salary
41000
36
• Can you write a single query that works for both second and third highest by
just changing one number?
• What if two employees are tied for the second-highest salary — does that affect
who counts as “third”?
Line-by-Line Explanation
• DISTINCT salary guarantees that tied salaries are treated as a single rank rather
than counted twice.
• ORDER BY salary DESC ranks salaries from highest to lowest.
• OFFSET (N - 1) skips the first N - 1 salaries and LIMIT 1 returns the very next
one — for N = 1 this returns the highest salary, for N = 2 the second-highest, and
so on.
• This single, parameterized pattern is exactly what Q34 and Q35 are special cases
of, which is why interviewers like to ask “second highest” first and then immedi-
ately ask “can you generalize that?”.
Expected Output
For N = 4 using the Q1 data (52000, 45000, 41000, 38000), the result is:
salary
38000
37
• Writing a completely different query for every value of N instead of recognizing
the reusable OFFSET pattern.
• Forgetting that OFFSET counts from 0, so the Nth highest needs OFFSET (N - 1),
not OFFSET N.
Similar Questions Interviewers Ask
• How would you solve this without LIMIT/OFFSET, using only a correlated subquery
that counts how many distinct salaries are greater? (an alternative fresher-
friendly approach interviewers sometimes expect: WHERE N - 1 = (SELECT
COUNT(DISTINCT salary) FROM Employee e2 WHERE [Link] > [Link]))
• Which is more portable across databases — LIMIT/OFFSET or the correlated sub-
query approach?
Line-by-Line Explanation
• GROUP BY department splits the table into one group per department.
• MAX(salary) is then computed separately within each group, giving the top
salary per department rather than one overall top salary.
Expected Output
department highest_salary
IT 52000
HR 38000
Finance 41000
38
Similar Questions Interviewers Ask
• Now show me the employee name along with the highest salary per department.
(Answer: join Employee to this grouped result on department and salary)
• What if you also need the second-highest salary per department? (This edges
toward window functions, which interviewers usually acknowledge is a step be-
yond the fresher level.)
SQL Solution
SELECT e.emp_name AS employee, [Link] AS employee_salary,
m.emp_name AS manager, [Link] AS manager_salary
FROM Employee e
JOIN Employee m
ON e.manager_id = m.emp_id
WHERE [Link] > [Link];
Line-by-Line Explanation
• As in Q23, the table is joined to itself: e represents the employee, m represents
that employee’s manager, matched through e.manager_id = m.emp_id.
• WHERE [Link] > [Link] then keeps only the pairs where the employee’s own
salary exceeds their manager’s salary.
• Employees with no manager (manager_id IS NULL) are automatically excluded
because a plain JOIN (inner join) requires a match.
Expected Output
39
• Using LEFT JOIN and forgetting to also filter out the NULL manager rows, which
would throw a comparison error or silently drop them depending on the database
(comparisons against NULL evaluate to unknown, not true).
• Mixing up which alias represents the employee and which represents the man-
ager, leading to a reversed or meaningless comparison.
Similar Questions Interviewers Ask
• How would you list every employee alongside their manager’s name, even if they
earn less? (switch to LEFT JOIN and drop the WHERE filter)
• Can this same logic be written with a correlated subquery instead of a self join?
Line-by-Line Explanation
• Rows are sorted by salary from highest to lowest.
• LIMIT 3 then keeps only the first three rows of that sorted list — the three em-
ployees with the highest salaries.
• DISTINCT here guards against duplicate (emp_name, salary) rows rather than
duplicate salary values, since the interviewer usually wants to see actual em-
ployees, not just three salary numbers.
Expected Output
emp_name salary
Kabir 52000
Aman 45000
Sneha 41000
40
Similar Questions Interviewers Ask
• How is this different from “top 3 distinct salaries”? (would need SELECT DISTINCT
salary ... LIMIT 3 without emp_name)
• How would you get the top 3 salaries per department instead of overall? (this
naturally leads into window functions, mentioned as a step beyond fresher scope)
Line-by-Line Explanation
• For every employee row (e1), a correlated subquery adds up the salaries of all
employees (e2) whose emp_id is less than or equal to the current row’s emp_id.
• This means row 1’s running total is just its own salary; row 2’s running total is
rows 1+2’s salaries added together; and so on — a classic cumulative sum.
• ORDER BY e1.emp_id makes sure the output is shown in the same order the run-
ning total was accumulated in.
Expected Output
41
that you know the window function exists, even while showing the subquery
version as the fresher-level answer.
Similar Questions Interviewers Ask
• Have you heard of window functions like SUM() OVER()? Can you explain what
they do at a high level?
• How would this query’s performance be affected on a very large table? (the
correlated subquery re-scans the table for every row, which is O(n²) and consid-
erably slower than a window function)
Line-by-Line Explanation
• CURDATE() - INTERVAL 12 MONTH computes the date exactly 12 months before
today.
• WHERE join_date >= ... keeps only employees who joined on or after that date,
i.e., within the last year.
• ORDER BY join_date DESC shows the most recently joined employees first, which
is usually what’s expected when the question is phrased this way.
Expected Output
A subset of the Employee table containing only employees hired within the last 12
months, sorted from most recent join date to least recent.
Common Interview Mistakes
• Using YEAR(join_date) = YEAR(CURDATE()) instead of a proper rolling 12-month
window — these are subtly different (calendar year vs. trailing 365 days) and
interviewers often probe which one was actually intended.
• Forgetting ORDER BY, which leaves the result in an unpredictable order even
though the filtering itself is correct.
Similar Questions Interviewers Ask
42
• How would you find employees who have completed exactly 1 year at the com-
pany?
• How would you group employees by the year they joined and count them?
43
Section C: Interview Revision Kit
Top 20 SQL Interview Tips
1. Always clarify the table schema out loud before writing a query if it isn’t fully
given to you.
2. Say your approach in plain English first, then write the SQL — interviewers care
as much about your thought process as the final query.
3. Never use SELECT * in a “real” solution you’re proposing for production — men-
tion this awareness even if you use it for quick testing.
4. Remember WHERE filters rows before grouping; HAVING filters groups after aggre-
gation.
5. Always use IS NULL / IS NOT NULL — never = NULL or != NULL.
6. Know the difference between COUNT(*), COUNT(column), and COUNT(DISTINCT
column) cold — this is asked almost everywhere.
7. Be ready to explain why NOT IN is risky with NULLs, and why NOT EXISTS is the
safer alternative.
8. Practice the “second highest / Nth highest salary” family until you can write it
without hesitation — it is the single most repeated SQL interview question across
all these companies.
9. When joining tables, always double check which table is “left” and which is
“right”, especially for LEFT JOIN.
10. If a LEFT JOIN isn’t giving you the unmatched rows you expect, check whether a
filter accidentally landed in WHERE instead of ON.
11. For self joins, always use two clearly different aliases and say out loud which
alias represents which “role” (e.g., employee vs manager).
12. Be able to explain SQL execution order from memory (see the section below) —
it’s one of the most common theory questions.
13. Know the difference between DELETE, TRUNCATE, and DROP even though this guide
doesn’t cover DDL in depth — it’s a frequent one-line follow-up.
14. When asked to “find duplicates”, default to GROUP BY + HAVING COUNT(*) > 1
unless told otherwise.
15. Practice writing the same query two ways (e.g., subquery vs JOIN, or subquery
vs CTE) — interviewers love asking “can you do this another way?”
16. Read every question twice — “top 3 salaries” and “top 3 distinct salaries” are
not the same thing, and interviewers use this distinction deliberately.
17. If you’re unsure about a database-specific function (LIMIT vs TOP, DATE_SUB vs
DATEADD), say so and explain the general logic — most interviewers accept either
syntax as long as the logic is right.
18. Don’t over-engineer a fresher-level answer with window functions unless asked
— a clean, correct subquery is usually exactly what’s expected.
19. Always mention time complexity or performance briefly if you use a correlated
subquery — showing awareness (e.g., “this re-scans the table for every row”) is
a strong signal to interviewers.
20. Stay calm on the whiteboard/notepad rounds — write the schema down first,
then build the query outward from FROM, not from SELECT.
44
SQL Query-Writing Strategy
When you’re given a fresh SQL problem in an interview, follow this order of thinking
rather than jumping straight to typing:
1. Understand the schema — list the tables, their columns, primary keys, and
foreign keys (draw them if needed).
2. Restate the question in your own words — this catches misunderstandings
early and shows the interviewer you’re thinking, not memorizing.
3. Identify which tables are needed — sometimes a question only needs one
table; don’t join unnecessarily.
4. Decide row-level vs group-level — does the question need GROUP BY, or is it
just filtering individual rows?
5. Write the FROM/JOIN first, even before SELECT — get the correct set of rows
before deciding what to display.
6. Add filters — decide what goes in WHERE (row-level) versus HAVING (group-level).
7. Add sorting and limiting — ORDER BY, LIMIT/TOP, only after the core logic is
right.
8. Sanity-check with sample data — mentally run your query against 2–3 sample
rows to check it behaves as expected, especially for NULLs and ties.
Key takeaway: because WHERE runs before SELECT, you cannot use a column alias
defined in SELECT inside a WHERE clause — but you can use it in ORDER BY, since ORDER
BY runs after SELECT.
45
GROUP BY vs HAVING
WHERE vs HAVING
46
JOIN Type Returns Common use case
RIGHT JOIN All rows from the Rarely used directly — usually
right table, rewritten as a LEFT JOIN by swapping
matched rows (or table order
NULL) from the
left
FULL OUTER JOIN All rows from both Reconciling two lists where either side
tables, matched may have unmatched rows (not
where possible, supported directly in MySQL;
NULL elsewhere emulated with UNION of LEFT and RIGHT
joins)
SELF JOIN A table joined to Employee-manager relationships,
itself using two hierarchy comparisons
aliases
CROSS JOIN Every row of one Rare in interviews; usually a mistake
table combined when the ON clause is missing
with every row of
another
47
• Filtering a LEFT JOIN’s right-hand table in WHERE, which silently turns it into an
INNER JOIN.
• Selecting non-aggregated, non-grouped columns alongside aggregate functions.
• Assuming row order is guaranteed without an explicit ORDER BY.
• Mixing up database-specific syntax (LIMIT/TOP, DATE_SUB/DATEADD) without real-
izing they aren’t universal.
• Forgetting that BETWEEN is inclusive of both endpoints.
• Not using table aliases in a self join, causing ambiguous column errors.
48
SELECT a.*
FROM TableA a
LEFT JOIN TableB b ON [Link] = b.a_id
WHERE b.a_id IS NULL;
CASE WHEN:
CASE
WHEN condition1 THEN result1
WHEN condition2 THEN result2
ELSE default_result
END
Keep this page open in the last five minutes before your interview — almost every
pattern on this sheet has appeared, in some form, in the 41 questions covered in this
guide.
49