Why SQL Is Asked in Every Tech Interview
SQL is the universal language of data. Whether you're joining a startup or a MAANG company, SQL is tested in almost every software engineer interview in India. Data engineers, backend engineers, fullstack developers, and even data scientists are expected to know SQL well.
This guide covers 60 of the most frequently asked SQL interview questions in India, organized from basic to advanced, with concise answers and code examples you can use directly in interviews.
What Indian companies test: Service companies (TCS, Infosys, Wipro) focus on basic SELECT, JOINs, GROUP BY, and simple subqueries. Product companies (Amazon, Flipkart, Paytm, Razorpay) go deeper — window functions, CTEs, query optimization, and indexing.
Basic SQL (Q1–Q15)
These questions are asked at every SQL interview, from fresher to 5-year experience. Master these before moving on.
Q1 · Basics
What is the difference between WHERE and HAVING?
WHERE filters individual rows before
HAVING filters groups after
GROUP BY. It cannot use aggregate functions (COUNT, SUM, etc.).HAVING filters groups after
GROUP BY. It can use aggregate functions.-- WHERE: filter rows before grouping SELECT department, COUNT(*) FROM employees WHERE salary > 50000 GROUP BY department; -- HAVING: filter groups after grouping SELECT department, COUNT(*) FROM employees GROUP BY department HAVING COUNT(*) > 5;
Q2 · Basics
What is the difference between DELETE, TRUNCATE, and DROP?
DELETE: Removes rows one by one. Can use
TRUNCATE: Removes all rows at once (no
DROP: Removes the entire table structure (schema + data). Cannot be rolled back. Table no longer exists after DROP.
WHERE to delete specific rows. Transactional — can be rolled back. Slower. Fires triggers.TRUNCATE: Removes all rows at once (no
WHERE). Faster (deallocates pages). Not easily rolled back in MySQL (in PostgreSQL it is transactional). Does not fire row-level triggers.DROP: Removes the entire table structure (schema + data). Cannot be rolled back. Table no longer exists after DROP.
Q3 · Constraints
What is the difference between PRIMARY KEY and UNIQUE KEY?
PRIMARY KEY: Uniquely identifies each row. Does NOT allow NULL values. Only one primary key per table (can be composite). Automatically creates a clustered index in MySQL InnoDB.
UNIQUE KEY: Also enforces uniqueness, but allows one NULL value (in most databases). A table can have multiple UNIQUE constraints. Creates a non-clustered index.
UNIQUE KEY: Also enforces uniqueness, but allows one NULL value (in most databases). A table can have multiple UNIQUE constraints. Creates a non-clustered index.
Q4 · Subqueries
What is the difference between a correlated and non-correlated subquery?
Non-correlated subquery: The inner query executes once and its result is used by the outer query. Independent of the outer query.
Correlated subquery: The inner query references the outer query and executes once for each row of the outer query. Much slower.
SELECT name FROM employees WHERE salary > (SELECT AVG(salary) FROM employees);
SELECT e1.name FROM employees e1 WHERE salary > (SELECT AVG(salary) FROM employees e2 WHERE e2.department = e1.department);
Q5 · NULL Handling
How do you handle NULL values in SQL?
NULL represents missing or unknown data. Key rules:
• Any comparison with NULL returns NULL (not true/false):
•
Useful functions:
• Any comparison with NULL returns NULL (not true/false):
NULL = NULL → NULL (use IS NULL instead)•
NULL + 5 → NULL. Aggregates ignore NULLs (SUM, AVG, COUNT(col) skip NULLs; COUNT(*) counts all rows).Useful functions:
COALESCE(col, 'default') — returns first non-NULL value. NULLIF(a, b) — returns NULL if a = b (useful to avoid division by zero). IFNULL(col, val) (MySQL), NVL(col, val) (Oracle).
Q6 · DISTINCT
What is the difference between DISTINCT and GROUP BY?
Both eliminate duplicates, but they are used for different purposes:
DISTINCT: Returns unique combinations of the selected columns. No aggregation.
GROUP BY: Groups rows to apply aggregate functions. Can do what DISTINCT does, but also allows
Performance: Modern optimizers often execute them similarly, but GROUP BY is more flexible.
DISTINCT: Returns unique combinations of the selected columns. No aggregation.
SELECT DISTINCT department FROM employees;
COUNT(), SUM(), etc. on groups.
SELECT department, COUNT(*) FROM employees GROUP BY department;
JOINs (Q16–Q25)
JOINs are the most commonly asked SQL topic in Indian interviews. Know all 4 types and when to use each.
Q16 · JOINs
What is the difference between INNER JOIN, LEFT JOIN, RIGHT JOIN, and FULL OUTER JOIN?
INNER JOIN: Returns only rows with a match in both tables.
LEFT JOIN: All rows from left + matching rows from right (NULL if no match).
RIGHT JOIN: All rows from right + matching rows from left (NULL if no match).
FULL OUTER JOIN: All rows from both — NULLs where no match.
CROSS JOIN: Cartesian product — every row of table A with every row of table B. O(m×n) rows. Rarely used directly.
LEFT JOIN: All rows from left + matching rows from right (NULL if no match).
RIGHT JOIN: All rows from right + matching rows from left (NULL if no match).
FULL OUTER JOIN: All rows from both — NULLs where no match.
SELECT e.name, d.dept_name FROM employees e LEFT JOIN departments d ON e.dept_id = d.id; -- employees without dept get NULL for dept_name
Q17 · Self JOIN
What is a SELF JOIN? Give an example.
A self JOIN joins a table with itself using table aliases. Classic use case: find employees and their managers (both stored in the same table).
Other uses: find pairs (e.g., find all pairs of employees in the same city), hierarchical data (org charts, category trees).
SELECT e.name AS employee, m.name AS manager FROM employees e LEFT JOIN employees m ON e.manager_id = m.id;
Q18 · Interview Problem
Find employees who earn more than their manager.
Classic LeetCode #181 — asked at Amazon, Flipkart, and JPMC India.
SELECT e.name AS Employee FROM Employee e INNER JOIN Employee m ON e.managerId = m.id WHERE e.salary > m.salary;
Window Functions (Q31–Q45)
Window functions are the most-asked advanced SQL topic at Indian product companies. Master ROW_NUMBER, RANK, DENSE_RANK, LEAD, and LAG.
Q31 · Window Functions
What are window functions? How are they different from GROUP BY?
Window functions perform calculations across a set of rows related to the current row without collapsing rows (unlike GROUP BY which produces one row per group).
The
The
OVER() clause defines the "window" of rows. PARTITION BY divides into groups. ORDER BY determines row order within the window.
-- GROUP BY: one row per department SELECT dept, AVG(salary) FROM emp GROUP BY dept; -- Window function: keeps all rows, adds avg per dept SELECT name, dept, salary, AVG(salary) OVER (PARTITION BY dept) AS dept_avg FROM emp;
Q32 · Ranking
What is the difference between ROW_NUMBER, RANK, and DENSE_RANK?
Given scores: 100, 90, 90, 80:
ROW_NUMBER: Unique sequential number — no ties.
RANK: Same rank for ties, but skips the next rank(s) — 2, 2, 4 (no 3).
DENSE_RANK: Same rank for ties, does NOT skip — 2, 2, 3.
Score | ROW_NUMBER | RANK | DENSE_RANK 100 | 1 | 1 | 1 90 | 2 | 2 | 2 90 | 3 | 2 | 2 80 | 4 | 4 | 3
RANK: Same rank for ties, but skips the next rank(s) — 2, 2, 4 (no 3).
DENSE_RANK: Same rank for ties, does NOT skip — 2, 2, 3.
Q33 · Interview Problem
Find the second highest salary in each department.
Classic interview problem — asked at Amazon, Google, and Flipkart:
Note:
WITH ranked AS ( SELECT name, department, salary, DENSE_RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS rnk FROM employees ) SELECT name, department, salary FROM ranked WHERE rnk = 2;
DENSE_RANK is used (not RANK) so that if two employees share rank 1, rank 2 still appears.
Q34 · LAG / LEAD
What are LAG and LEAD window functions? Give a use case.
LAG(col, n): Returns the value of
LEAD(col, n): Returns the value of
Use case: Calculate month-over-month revenue growth:
col from n rows before the current row in the window.LEAD(col, n): Returns the value of
col from n rows after the current row.Use case: Calculate month-over-month revenue growth:
SELECT month, revenue, LAG(revenue) OVER (ORDER BY month) AS prev_month_revenue, revenue - LAG(revenue) OVER (ORDER BY month) AS growth FROM monthly_revenue;
Q35 · CTE
What is a CTE (Common Table Expression)? How is it different from a subquery?
A CTE is a named temporary result set defined with
CTE vs Subquery: CTEs are more readable, can be recursive (for hierarchical data), and can be referenced multiple times. Subqueries are inline and can't be reused in the same query.
WITH. It can be referenced multiple times in the same query, making complex queries more readable.
WITH dept_avg AS ( SELECT dept_id, AVG(salary) AS avg_sal FROM employees GROUP BY dept_id ) SELECT e.name, e.salary, d.avg_sal FROM employees e JOIN dept_avg d ON e.dept_id = d.dept_id WHERE e.salary > d.avg_sal;
Indexes & Query Optimization (Q46–Q55)
Index questions are asked at product companies, especially for data-heavy systems. Know when indexes help, when they hurt, and how to check query plans.
Q46 · Indexes
What is a database index? What are the types of indexes?
An index is a data structure (usually a B-tree or hash) that speeds up data retrieval at the cost of additional storage and slower write operations.
Types:
• Clustered index: Determines the physical order of data in the table. One per table. In MySQL InnoDB, the primary key IS the clustered index.
• Non-clustered index: Separate structure that stores index key + pointer to actual row. Multiple allowed per table.
• Composite index: Index on multiple columns. Follows "leftmost prefix" rule — useful for queries filtering on the first column(s) of the index.
• Covering index: An index that includes all columns needed by the query — no need to look up the actual row (index-only scan, very fast).
• Full-text index: For text search (
Types:
• Clustered index: Determines the physical order of data in the table. One per table. In MySQL InnoDB, the primary key IS the clustered index.
• Non-clustered index: Separate structure that stores index key + pointer to actual row. Multiple allowed per table.
• Composite index: Index on multiple columns. Follows "leftmost prefix" rule — useful for queries filtering on the first column(s) of the index.
• Covering index: An index that includes all columns needed by the query — no need to look up the actual row (index-only scan, very fast).
• Full-text index: For text search (
MATCH ... AGAINST). Different from B-tree.
Q47 · Optimization
When should you NOT use an index?
Indexes can actually hurt performance in these cases:
1. Low-cardinality columns: A column with only 2 values (e.g., boolean gender) — the optimizer may prefer a full table scan.
2. Small tables: Full scan is faster than index lookup + row fetch for tiny tables.
3. Heavy write tables: Every INSERT/UPDATE/DELETE must update all indexes — too many indexes slow down writes.
4. Functions on indexed columns:
1. Low-cardinality columns: A column with only 2 values (e.g., boolean gender) — the optimizer may prefer a full table scan.
2. Small tables: Full scan is faster than index lookup + row fetch for tiny tables.
3. Heavy write tables: Every INSERT/UPDATE/DELETE must update all indexes — too many indexes slow down writes.
4. Functions on indexed columns:
WHERE YEAR(created_at) = 2026 — function prevents index use. Use range instead: WHERE created_at BETWEEN '2026-01-01' AND '2026-12-31'.
Q48 · EXPLAIN
How do you check if a query is using an index? What is EXPLAIN?
Run
Key fields in MySQL EXPLAIN:
• type:
• key: Which index was used. NULL means no index.
• rows: Estimated rows examined. Lower is better.
• Extra: "Using filesort" and "Using temporary" are warning signs of inefficiency.
EXPLAIN SELECT ... before your query. The output shows the query execution plan:Key fields in MySQL EXPLAIN:
• type:
ALL = full table scan (bad), index = full index scan, range = index range scan, ref / eq_ref = efficient index lookup (good).• key: Which index was used. NULL means no index.
• rows: Estimated rows examined. Lower is better.
• Extra: "Using filesort" and "Using temporary" are warning signs of inefficiency.
Transactions & ACID (Q56–Q60)
Transaction questions are asked at companies building financial systems (Paytm, Razorpay, PhonePe, JPMC). Know ACID, isolation levels, and common anomalies.
Q56 · ACID
What does ACID stand for in database transactions?
Atomicity: A transaction is "all or nothing" — either all operations succeed or none take effect. If one step fails, the entire transaction is rolled back.
Consistency: A transaction brings the database from one valid state to another, maintaining all defined rules (constraints, cascades, triggers).
Isolation: Concurrent transactions execute as if they were serial. One transaction's intermediate state is not visible to others (level depends on isolation setting).
Durability: Once a transaction commits, it persists even if the system crashes — typically ensured by write-ahead logging (WAL).
Consistency: A transaction brings the database from one valid state to another, maintaining all defined rules (constraints, cascades, triggers).
Isolation: Concurrent transactions execute as if they were serial. One transaction's intermediate state is not visible to others (level depends on isolation setting).
Durability: Once a transaction commits, it persists even if the system crashes — typically ensured by write-ahead logging (WAL).
Q57 · Isolation
What are the four transaction isolation levels and what anomalies do they prevent?
Isolation Level | Dirty Read | Non-repeatable Read | Phantom Read READ UNCOMMITTED | Yes | Yes | Yes READ COMMITTED | No | Yes | Yes REPEATABLE READ | No | No | Yes SERIALIZABLE | No | No | No
Non-repeatable Read: Same query returns different data if another transaction commits in between.
Phantom Read: A query returns different sets of rows if another transaction inserts/deletes rows in between.
MySQL InnoDB default:
REPEATABLE READ. PostgreSQL default: READ COMMITTED.
Q58 · Interview Problem
Write a query to find duplicate rows in a table.
Find duplicate emails in a Users table (LeetCode #182):
To find and delete duplicates while keeping one (using CTE + ROW_NUMBER):
SELECT email FROM Person GROUP BY email HAVING COUNT(id) > 1;
WITH cte AS ( SELECT id, ROW_NUMBER() OVER (PARTITION BY email ORDER BY id) AS rn FROM Person ) DELETE FROM Person WHERE id IN (SELECT id FROM cte WHERE rn > 1);
Q59 · Interview Problem
Find the Nth highest salary from a table.
Using window functions (cleanest approach for modern MySQL/PostgreSQL):
Alternative without window functions (for older MySQL):
SELECT DISTINCT salary AS NthHighestSalary FROM ( SELECT salary, DENSE_RANK() OVER (ORDER BY salary DESC) AS rnk FROM Employee ) ranked WHERE rnk = N; -- replace N with the desired rank
SELECT MAX(salary) FROM Employee WHERE salary < (SELECT MAX(salary) FROM Employee); -- 2nd highest
Q60 · Interview Problem
Write a query to find customers who have placed more than 3 orders in the last 30 days.
SELECT customer_id, COUNT(*) AS order_count FROM orders WHERE order_date >= CURDATE() - INTERVAL 30 DAY GROUP BY customer_id HAVING COUNT(*) > 3 ORDER BY order_count DESC;
CURRENT_DATE - INTERVAL '30 days'. This uses a WHERE clause for date filtering (which can use an index on order_date) combined with HAVING for the aggregate filter — demonstrating both WHERE vs HAVING knowledge.
Common SQL interview mistake: Using
WHERE on an aggregated column. Always remember — if you're filtering on COUNT(), SUM(), or any aggregate, use HAVING, not WHERE. This mistake alone disqualifies many candidates.