<DataInsights />
  • 🏠 Home
  • πŸ“Š SQL
  • 🐍 Python
  • πŸ“ˆ Power BI
  • πŸ“— Excel
  • πŸ’Ό Career
  • 🎯 Interview Q&A
  • πŸ“ Case Study
  • πŸ“₯ Downloads
  • πŸš€ My Portfolio
<DataInsights />

Practical Data Analytics tutorials covering SQL, Python, Power BI, Excel and career guidance for aspiring analysts β€” 100% free.

Topics

  • SQL Tutorials
  • Python Guide
  • Power BI
  • Excel Tips
  • Career Guide

Quick Links

  • πŸ› οΈ All Tools
  • πŸ—“οΈ Archive
  • πŸ“¬ Contact
  • πŸ” Search
  • Portfolio
  • Kaggle
  • GitHub

Legal & Info

  • About
  • Contact
  • Privacy Policy
  • Disclaimer
  • Terms & Conditions
  • DMCA
  • Sitemap
Copyright © 2026 Data Insights by Jatin Kumar. All Rights Reserved.Built with ❀️ for Data Analysts
Home/Interview Q&A/Top 30 Advanced SQL Interview Questions And Answer...

Top 30 Advanced SQL Interview Questions And Answers

A
August 4, 2026 Jatin Kumar 22 min read Interview Q&A
Data Insights Interview Prep β€” SQL Advanced

Top 30 Advanced SQL Interview Questions & Answers

Window Functions, CTEs, Recursive Queries, Stored Procedures, Query Optimization, EXPLAIN Plan aur real-world scenario-based questions β€” yeh 2+ years experience level ke liye hain. Har question mein Answer (English), Explanation (Hinglish) aur SQL Query. Data Insights par.

πŸ“‘ Topics Covered:

  • Window Functions β€” ROW_NUMBER, RANK, DENSE_RANK, NTILE (Q1-Q6)
  • Window Functions β€” LAG, LEAD, Running Totals, Moving Avg (Q7-Q11)
  • CTEs β€” WITH Clause & Recursive CTEs (Q12-Q15)
  • Stored Procedures & Triggers (Q16-Q18)
  • Query Optimization & EXPLAIN (Q19-Q22)
  • Advanced Scenario Questions (Q23-Q30)

πŸ“‹ Level: Advanced β€” 2+ Years Experience. Window Functions aur CTEs modern SQL ka core hain β€” har senior-level interview mein puchhe jaate hain. Prerequisite: Basic + Intermediate SQL Interview Questions (Data Insights par available).

Q1: What are Window Functions in SQL?

Answer: Window Functions perform calculations across a set of table rows that are related to the current row β€” called a "window." Unlike GROUP BY (which collapses rows into groups), Window Functions retain all individual rows while adding calculated values. They use the OVER() clause to define the window. Types: Ranking (ROW_NUMBER, RANK, DENSE_RANK), Aggregate (SUM, AVG, COUNT over window), Value (LAG, LEAD, FIRST_VALUE, LAST_VALUE).

🎯 Explanation: GROUP BY mein 100 rows β†’ 5 groups (rows collapse ho jaati hain). Window Functions mein 100 rows β†’ 100 rows PLUS har row ke saath ek extra calculated column (rows collapse nahi hoti). Jaise "har employee ke saath uske department ki average salary bhi dikhao" β€” GROUP BY se nahi ho sakta (rows collapse hongi), Window Function se ho jaayega. OVER() ke andar PARTITION BY (group define karo) aur ORDER BY (sort karo) likhte hain.

-- Window Function syntax:
-- function_name() OVER (PARTITION BY col ORDER BY col)
-- Show each employee's salary
WITH their department average
SELECT name, department, salary,
AVG(salary) OVER
(PARTITION BY department) AS dept_avg

FROM employees;

name β”‚ department β”‚ salaryβ”‚ dept_avg
Amit Kumar β”‚ Sales β”‚ 55000 β”‚ 58000 ← All Sales rows
Ravi Sharmaβ”‚ Sales β”‚ 61000 β”‚ 58000 show same avg
Priya Patelβ”‚ IT β”‚ 72000 β”‚ 67000 ← All IT rows
Neha Gupta β”‚ IT β”‚ 62000 β”‚ 67000
show same avg Note: ALL rows retained β€” no collapsing!

Q2: What is ROW_NUMBER()?

Answer: ROW_NUMBER() assigns a unique sequential integer to each row within a partition. Even if two rows have the same value, they get different row numbers. It always produces unique, consecutive numbers: 1, 2, 3, 4...

🎯 Explanation: ROW_NUMBER() = serial number dena β€” har row ko unique number milta hai, chahe values same hon. PARTITION BY se groups banao β€” har group mein numbering 1 se start hoti hai. ORDER BY se sequence define karo β€” "salary descending se number do." Sabse zyada use hota hai β€” "har department ka top earner dikhao" ya "duplicate rows mein se ek rakho."

-- Row number within each department (sorted by salary desc)
SELECT name, department, salary,
ROW_NUMBER()
OVER ( PARTITION BY
department ORDER BY salary DESC )
AS rn

FROM employees;
name        β”‚ department β”‚ salaryβ”‚ rn 
Priya Patel β”‚ IT         β”‚ 72000 β”‚ 1 ← Top earner in IT 
Neha Gupta  β”‚ IT         β”‚ 62000 β”‚ 2 
Ravi Sharma β”‚ Sales      β”‚ 61000 β”‚ 1 ← Top earner in Sales 
Amit Kumar  β”‚ Sales      β”‚ 55000 β”‚ 2

Q3: What is the difference between ROW_NUMBER, RANK, and DENSE_RANK?

Answer: All three assign rankings, but handle ties (equal values) differently. ROW_NUMBER gives unique numbers regardless of ties. RANK gives same rank for ties but SKIPS numbers after. DENSE_RANK gives same rank for ties but does NOT skip β€” next rank is consecutive.

SELECT name, salary,
ROW_NUMBER()OVER
(ORDER BY salary DESC)
AS row_num,RANK()
OVER (ORDER BY salary
DESC) AS rnk,
DENSE_RANK() OVER
(ORDER BY salary DESC)
AS dense_rnk
FROM employees;
Priya72000111
Neha62000222
Ravi62000322 ← TIE
Amit55000443 ← RANK skips 3, DENSE doesn't
Rahul48000554
ROW_NUMBER: 1, 2, 3, 4, 5 (always unique) 
RANK: 1, 2, 2, 4, 5 (tie=same, then SKIP) 
DENSE_RANK: 1, 2, 2, 3, 4 (tie=same, NO skip)

🎯 Explanation: ROW_NUMBER = serial number (hamesha unique). RANK = competition ranking (2 logon ko tied 2nd mila, next 4th β€” 3rd skip). DENSE_RANK = dense ranking (2 logon ko tied 2nd, next 3rd β€” skip nahi). Interview mein puchha jaata hai: "Nth highest salary DENSE_RANK se nikalo" β€” kyunki ties handle hote hain properly.

Q4: Find Nth Highest Salary using Window Function

Answer: Use DENSE_RANK() with a CTE or subquery. DENSE_RANK handles ties correctly β€” if two people have the same salary, they share the same rank and the next distinct salary gets the next rank.

🎯 Explanation: Intermediate mein LIMIT OFFSET method dekha tha β€” lekin woh ties handle nahi karta properly. Advanced approach: DENSE_RANK() se har unique salary ko rank do, phir WHERE rank = N karke Nth highest nikalo. Yeh production-grade solution hai β€” ties bhi handle hote hain aur department-wise Nth salary bhi nikal sakte ho PARTITION BY se.

-- Find 3rd highest salary (overall)
WITH ranked_salaries
AS ( SELECT name, salary,
DENSE_RANK() OVER
(ORDER BY salary DESC)
AS rnk FROM employees )
SELECT name, salary
FROM ranked_salaries

WHERE rnk = 3;

-- Nth highest salary PER DEPARTMENT
WITH
dept_ranked AS ( SELECT
name, department, salary, DENSE_RANK() OVER
( PARTITION BY department ORDER BY
salary DESC ) AS rnk
FROM employees ) SELECT *

FROM dept_ranked
WHERE rnk = 2
;
-- 2nd highest salary in EACH department!

Q5: What is NTILE()?

Answer: NTILE(n) divides ordered rows into n approximately equal groups (buckets) and assigns a bucket number to each row. If rows cannot be divided equally, earlier buckets get one extra row.

🎯 Explanation: NTILE(4) = data ko 4 equal groups (quartiles) mein baanto. 100 employees hain β€” NTILE(4) se Q1 (top 25), Q2, Q3, Q4 (bottom 25) ban jayenge. HR analytics mein use hota hai β€” "top 25% performers" identify karo. NTILE(3) = tertiles, NTILE(10) = deciles, NTILE(100) = percentiles.

-- Divide employees into 4 salary quartiles
SELECT name, salary, NTILE
(4) OVER
(ORDER BY salary DESC)
AS quartile
FROM employees;

-- Use: Find top 25% earners (quartile = 1)
WITH
quartiles AS ( SELECT *,
NTILE(4)
OVER (ORDER BY salary
DESC) AS q
FROM employees ) SELECT *

FROM quartiles
WHERE q = 1;

Q6: What is PARTITION BY vs GROUP BY?

Answer: GROUP BY collapses rows into summary groups β€” you lose individual row details. PARTITION BY (used in Window Functions) groups rows for calculation purposes but retains ALL individual rows in the output.

Feature GROUP BY PARTITION BY
Rows in output Collapsed β€” one row per group ALL individual rows retained
Used with Aggregate functions (SUM, COUNT) Window functions (OVER clause)
Individual details? ❌ Lost β€” only grouped columns + aggregates βœ… Retained β€” all columns available

🎯 Explanation: GROUP BY = summary chahiye (har department ki avg salary β€” 5 departments = 5 rows). PARTITION BY = detail ke saath summary chahiye (har employee ke saath uski department ki avg salary β€” 100 employees = 100 rows). Yeh sabse important difference hai β€” interview mein 100% puchha jaata hai!

Q7: What are LAG() and LEAD()?

Answer: LAG() accesses a value from a PREVIOUS row without self-join. LEAD() accesses a value from the NEXT row. Both accept offset (how many rows back/forward, default 1) and default value (if no previous/next row exists, returns this instead of NULL).

🎯 Explanation: LAG = "pichli row ki value dikhao." LEAD = "agli row ki value dikhao." Month-over-Month comparison ke liye perfect β€” "is month ki sales aur pichle month ki sales ek row mein dikhao." MoM Growth = (Current - LAG) / LAG. Bina LAG/LEAD ke yeh kaam self-join se karna padta β€” complex aur slow. LAG/LEAD simple aur fast hai.

-- Monthly sales with previous month comparison
SELECT month_name, total_sales, LAG
(total_sales, 1, 0)
OVER (ORDER BY month_num)
AS prev_month_sales, total_sales - LAG
(total_sales, 1, 0)
OVER (ORDER BY month_num)
AS mom_change, LEAD(total_sales,
1) OVER
(ORDER BY month_num) AS
next_month_sales
FROM monthly_sales;
month    β”‚ name   β”‚ total_sales β”‚ prev_month β”‚ mom_change 
January  β”‚ 115000 β”‚ 0           β”‚ 115000     β”‚ 24000
February β”‚ 24000  β”‚ 115000      β”‚ -91000     β”‚ 18000 
March    β”‚ 18000  β”‚ 24000       β”‚ -6000      β”‚ 7500 
April    β”‚ 7500   β”‚ 18000       β”‚ -10500     β”‚ NULL

Q8: How to calculate Running Total using Window Function?

Answer: Use SUM() as a window function with ORDER BY. The frame automatically becomes ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW β€” accumulating from start to current row.

🎯 Explanation: Running Total = har row par pichle saare rows ka total + current row. SUM() OVER(ORDER BY date) automatically cumulative sum karta hai β€” ORDER BY lagane se frame default "beginning se current row tak" ban jaata hai. Yeh self-join approach se bahut clean aur fast hai.

-- Running Total of monthly sales
SELECT month_name, total_sales,
SUM(total_sales) OVER
(ORDER BY month_num) AS running_total

FROM monthly_sales;
-- Running Total PER department
SELECT department, order_date, amount, SUM(amount)
OVER ( PARTITION BY
department ORDER BY order_date ) AS
dept_running_total
FROM orders;

Q9: How to calculate Moving Average using Window Frame?

Answer: Use AVG() with ROWS BETWEEN clause to define the sliding window. ROWS BETWEEN 2 PRECEDING AND CURRENT ROW creates a 3-row moving average (current + 2 previous rows).

🎯 Explanation: Moving Average = sliding window ka average. 3-month moving average = "current month + pichle 2 months ka average." ROWS BETWEEN 2 PRECEDING AND CURRENT ROW = current row aur usse pehle ki 2 rows β€” total 3 rows ka window. Yeh window har row ke saath slide karta hai. Trend analysis aur seasonality smoothing mein bahut use hota hai.

-- 3-month moving average
SELECT month_name, total_sales, ROUND
(AVG(total_sales) OVER
( ORDER BY month_num ROWS BETWEEN
2 PRECEDING AND CURRENT ROW ),
0) AS moving_avg_3m

FROM monthly_sales;

Q10: What are FIRST_VALUE() and LAST_VALUE()?

Answer: FIRST_VALUE() returns the first value in an ordered partition. LAST_VALUE() returns the last value. LAST_VALUE requires explicit frame (ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) β€” otherwise default frame gives wrong results.

SELECT name, department, salary, FIRST_VALUE
(name) OVER ( PARTITION BY
department ORDER BY salary DESC
) AS highest_earner, LAST_VALUE
(name) OVER ( PARTITION BY department
ORDER BY salary DESC
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING )
AS lowest_earner
FROM
employees;

⚑ Important: LAST_VALUE mein explicit frame MANDATORY hai β€” bina frame ke default "CURRENT ROW tak" hota hai β€” galat result aata hai. Hamesha ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING likho LAST_VALUE ke saath.

Q11: What is Window Frame (ROWS BETWEEN)?

Answer: Window Frame defines exactly which rows relative to the current row are included in the window function's calculation. It specifies the start and end boundaries of the window.

Common Window Frame Options:
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
← Running Total (default with ORDER BY) ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
← Entire partition ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
← Last 3 rows (moving avg) ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
← Current Β± 1 row (centered avg) ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
← Current to
end

🎯 Explanation: Window Frame = "kaunsi rows include karni hain calculation mein." UNBOUNDED PRECEDING = partition ki sabse pehli row. CURRENT ROW = abhi wali row. UNBOUNDED FOLLOWING = partition ki sabse aakhri row. "2 PRECEDING" = current se 2 row peeche. Frame define karna bahut important hai β€” especially LAST_VALUE aur Moving Averages ke liye.

Q12: What is a CTE (Common Table Expression)?

Answer: A CTE (Common Table Expression) is a temporary named result set defined using the WITH clause. It exists only during the execution of that query. CTEs improve readability, allow breaking complex queries into steps, and can be referenced multiple times in the main query.

🎯 Explanation: CTE ek temporary variable hai β€” jaise DAX mein VAR. Pehle ek result calculate karo (WITH block mein), naam do, phir main query mein use karo. Complex queries ko steps mein todne ke liye perfect hai. Subquery se zyada readable hai aur multiple baar reference kar sakte ho. CTE query ke end hone ke baad khatam ho jaata hai β€” stored nahi hota.

-- CTE: Department stats, then filter
WITH dept_stats AS
( SELECT department, AVG
(salary) AS avg_sal, COUNT
(*) AS emp_count FROM
employees GROUP BY department )
SELECT *
FROM dept_stats

WHERE avg_sal > 55000
AND emp_count > 3;

-- Multiple CTEs
WITH sales_data
AS ( SELECT product_id,
SUM(amount) AS total
FROM orders GROUP BY product_id ), product_data
AS ( SELECT product_id, product_name, category
FROM products ) SELECT
p.product_name, s.total
FROM sales_data s

JOIN product_data p
ON
s.product_id = p.product_id;

Q13: CTE vs Subquery vs Temp Table β€” Kab Kya?

Feature CTE (WITH) Subquery Temp Table
Scope Single query Single query Entire session
Reusable? Multiple times in same query Only where defined Multiple queries in session
Readability Best β€” named steps Poor if nested Good β€” named table
Stored? No β€” in memory only No Yes β€” temporary storage
Best for Complex queries, recursion Simple filtering Large intermediate results

Q14: What is a Recursive CTE?

Answer: A Recursive CTE references itself in its definition β€” creating a loop. It has two parts: an anchor query (base case) and a recursive query (references the CTE itself). Recursion continues until no new rows are produced or a limit is reached. Used for hierarchical data (org charts, file systems, category trees).

-- Recursive CTE: Employee org hierarchy
WITH RECURSIVE org_chart
AS ( -- Anchor: Top-level manager (no manager_id)
SELECT emp_id, name, manager_id, 1
AS level FROM employees
WHERE manager_id IS NULL
UNION ALL -- Recursive: Employees reporting to previous level
SELECT e.emp_id, e.name, e.manager_id, oc.level + 1
FROM employees e INNER JOIN org_chart oc
ON e.manager_id = oc.emp_id ) SELECT *
FROM
org_chart
ORDER BY level;

🎯 Explanation: Recursive CTE = khud ko call karta hai β€” loop jaisa. Anchor = starting point (CEO, jiska koi manager nahi). Recursive = "is level ke employees ke neeche kaun report karta hai?" β€” yeh tab tak chalta hai jab tak aur koi nahi bachta. Org chart, category tree, bill of materials β€” hierarchical data ke liye perfect hai.

Q15: Generate a Number/Date Series using Recursive CTE

-- Generate numbers 1 to 10
WITH RECURSIVE numbers AS
( SELECT 1
AS n UNION ALL
SELECT n + 1
FROM numbers WHERE n <
10 ) SELECT n
FROM numbers;

-- Generate date series for 2026
WITH RECURSIVE dates
AS ( SELECT '2026-01-01'
AS dt UNION ALL SELECT
DATE_ADD(dt, INTERVAL 1
DAY) FROM dates
WHERE dt < '2026-12-31' )
SELECT dt
FROM dates;

Q16: What is a Stored Procedure?

Answer: A Stored Procedure is a saved collection of SQL statements that can be executed as a single unit by calling its name. It can accept input parameters, perform logic, and return results. Stored Procedures are precompiled β€” faster execution, reusable, and maintain consistency.

-- Create Stored Procedure DELIMITER
// CREATE PROCEDURE GetEmployeesByDept( IN
dept_name VARCHAR(50) )
BEGIN SELECT emp_id, name, salary

FROM employees
WHERE department = dept_name

ORDER BY salary DESC;
END
// DELIMITER ;
-- Call the Stored Procedure
CALL GetEmployeesByDept('Sales');

🎯 Explanation: Stored Procedure = saved recipe β€” ek baar banao, baar baar use karo. Complex query baar baar likhne ki jagah β€” procedure banao, naam do, CALL karo. Parameters pass kar sakte ho (IN = input, OUT = output). Precompiled hota hai β€” fast execution. Security: users ko direct table access mat do β€” sirf procedure execute karne do.

Q17: Stored Procedure vs Function β€” Kya Difference Hai?

Feature Stored Procedure Function
Returns Can return 0, 1, or multiple values Must return exactly ONE value
Call syntax CALL procedure_name() Used inside SELECT statements
DML operations βœ… INSERT/UPDATE/DELETE allowed ❌ Not allowed (read-only)
Use in WHERE ❌ Cannot βœ… Can use in WHERE, SELECT

Q18: What is a Trigger in SQL?

Answer: A Trigger is a stored program that automatically executes (fires) when a specific event (INSERT, UPDATE, DELETE) occurs on a table. Triggers can run BEFORE or AFTER the event. They are used for audit logging, data validation, and automatic data updates.

-- Audit Trigger: Log salary changes CREATE TRIGGER salary_audit AFTER

UPDATE
ON employees FOR EACH ROW BEGIN IF OLD.salary <> NEW.salary
THEN
INSERT INTO salary_audit_log (emp_id, old_salary, new_salary, changed_at)
VALUES (NEW.emp_id, OLD.salary, NEW.salary, NOW());
END IF;
END;

🎯 Explanation: Trigger = automatic alarm. Jab koi salary update kare β€” trigger automatically old salary aur new salary audit log mein save kar deta hai. Manually kuch karne ki zaroorat nahi. OLD = update se pehle ki value. NEW = update ke baad ki value. BEFORE triggers data validate karne ke liye (insert se pehle check karo). AFTER triggers logging ke liye.

Q19: How to Optimize SQL Queries?

Answer: Query optimization reduces execution time and resource usage. Key techniques:

  • SELECT specific columns instead of SELECT * β€” less data transferred
  • Use proper indexes on WHERE, JOIN, ORDER BY columns
  • Avoid SELECT DISTINCT unless necessary β€” sorting overhead
  • Use EXISTS instead of IN for large subqueries β€” short-circuit evaluation
  • Avoid functions on indexed columns in WHERE β€” index won't be used. WHERE YEAR(date) = 2026 ❌ β†’ WHERE date BETWEEN '2026-01-01' AND '2026-12-31' βœ…
  • Use LIMIT when full result not needed
  • Avoid correlated subqueries β€” use JOINs instead
  • Use UNION ALL instead of UNION when duplicates don't matter
  • Optimize JOINs β€” smaller table as driving table, indexed join columns
  • Use EXPLAIN to analyze query execution plan

Q20: What is EXPLAIN and how to read it?

Answer: EXPLAIN shows the query execution plan β€” how MySQL will execute a query. It reveals which indexes are used, join order, scan type, estimated rows, and other optimization details.

EXPLAIN SELECT *
FROM employees
WHERE department = 'Sales' AND salary > 50000;
 Key EXPLAIN columns to look at: ═══════════════════════════════════════════════ type: ALL (bad-full scan), index, range, ref, const (best) key: Which index is being used (NULL = no index!) rows: Estimated rows to scan (lower = better) Extra: "Using filesort" (slow), "Using index" (good) Goal: type should be "ref" or "range", not "ALL" key should NOT be NULL rows should be as low as possible

Q21: What is Normalization? Explain Normal Forms.

Answer: Normalization organizes database tables to reduce redundancy and improve data integrity. Normal forms are progressive rules:

Normal Form Rule Simple Explanation
1NF Atomic values β€” no multi-valued columns Ek cell mein ek hi value β€” "Delhi, Mumbai" ❌ β†’ alag rows βœ…
2NF 1NF + no partial dependency Non-key columns must depend on FULL primary key
3NF 2NF + no transitive dependency Non-key columns depend ONLY on primary key, not on other non-keys

Q22: What is Denormalization and when to use it?

Answer: Denormalization is intentionally adding redundancy back into a normalized database to improve READ performance. It reduces JOINs by storing duplicate data in fewer tables. Used in data warehouses and reporting databases where read speed is critical.

🎯 Explanation: Normalization = data clean, no redundancy, but zyada JOINs (slow reads). Denormalization = some redundancy, fewer JOINs (fast reads). OLTP databases (banking, transactions) = Normalized (data integrity priority). OLAP databases (reporting, analytics) = Denormalized (query speed priority). Data Analyst ke liye β€” tum mostly denormalized data par kaam karte ho (star schema, flat tables).

Q23: Find Top N Records Per Group

-- Top 3 earners in each department WITH ranked AS (
SELECT *, ROW_NUMBER() OVER ( PARTITION BY department ORDER BY salary DESC ) AS rn
FROM employees ) SELECT *
FROM ranked
WHERE rn <= 3;

Q24: Find Year-over-Year Growth in SQL

WITH yearly AS ( SELECT YEAR(order_date) AS yr, SUM(amount) AS total_sales FROM orders GROUP BY YEAR(order_date) ) SELECT yr,
total_sales, LAG(total_sales) OVER (ORDER BY yr) AS prev_year,
ROUND( (total_sales - LAG(total_sales) OVER (ORDER BY yr)) / LAG(total_sales) OVER (ORDER BY yr) * 100, 1 ) AS yoy_growth_pct
FROM yearly;

Q25: Find Consecutive Login Days for Users

-- Find users with 3+ consecutive login days WITH login_groups AS (
SELECT user_id, login_date, DATE_SUB(login_date, INTERVAL ROW_NUMBER() OVER ( PARTITION BY user_id ORDER BY login_date ) DAY ) AS grp
FROM logins ) SELECT user_id, MIN(login_date) AS streak_start,
MAX(login_date) AS streak_end, COUNT(*) AS consecutive_days
FROM login_groups
GROUP BY user_id, grp
HAVING COUNT(*) >= 3;

🎯 Explanation: Yeh "Islands and Gaps" problem hai β€” classic advanced SQL. Trick: login_date minus ROW_NUMBER = same group for consecutive days. Agar dates consecutive hain toh minus ROW_NUMBER same value dega (group identifier). Non-consecutive dates alag group banayengi. Bahut popular interview question hai!

Q26: Find Gaps in Sequential Data

-- Find missing order IDs in sequence
SELECT order_id + 1 AS gap_start, LEAD(order_id) OVER (ORDER BY order_id) - 1 AS gap_end
FROM orders
WHERE LEAD(order_id) OVER (ORDER BY order_id) - order_id > 1;

Q27: Pivot Rows to Columns using CASE WHEN

-- Monthly sales as columns (pivot)
SELECT product_name, SUM(CASE WHEN MONTH(order_date) = 1 THEN amount ELSE 0 END) AS Jan,
SUM(CASE WHEN MONTH(order_date) = 2 THEN amount ELSE 0 END) AS Feb,
SUM(CASE WHEN MONTH(order_date) = 3 THEN amount ELSE 0 END) AS Mar
FROM orders o
JOIN products p
ON o.product_id = p.product_id
GROUP BY product_name;

Q28: Find Employees Earning More Than Their Manager

SELECT e.name AS employee, e.salary AS emp_salary, m.name AS manager,
m.salary AS mgr_salary
FROM employees e
JOIN employees m
ON e.manager_id = m.emp_id
WHERE e.salary > m.salary;

🎯 Explanation: Classic SELF JOIN question β€” employees table khud se join hoti hai. e = employee, m = manager. e.manager_id = m.emp_id se manager find karo. WHERE e.salary > m.salary β€” employee ki salary manager se zyada. Yeh LeetCode/HackerRank ka famous problem hai!

Q29: Calculate Percentage of Total Per Group

-- Each product's % of total sales (Window Function approach) SELECT product_name, total_sales, ROUND( total_sales * 100.0 / SUM(total_sales) OVER (), 1 ) AS pct_of_total FROM ( SELECT product_name, SUM(amount) AS total_sales FROM orders o JOIN products p ON o.product_id = p.product_id GROUP BY product_name ) AS t ORDER BY pct_of_total DESC; -- SUM() OVER() without PARTITION BY = grand total -- Each row's sales / grand total Γ— 100 = percentage

Q30: Remove Duplicates Using ROW_NUMBER (Keep Latest)

-- Keep latest record per email, delete older duplicates WITH ranked AS (
SELECT *, ROW_NUMBER() OVER ( PARTITION BY email ORDER BY created_at DESC ) AS rn
FROM employees ) -- View duplicates (verify before deleting) SELECT *
FROM ranked
WHERE rn > 1;
-- Delete duplicates (keep latest β€” rn = 1) DELETE FROM employees WHERE emp_id IN ( SELECT emp_id FROM (
SELECT emp_id, ROW_NUMBER() OVER ( PARTITION BY email ORDER BY created_at DESC ) AS rn
FROM employees ) AS temp
WHERE rn > 1 );

🎯 Explanation: Advanced approach β€” ROW_NUMBER() se har duplicate group mein latest record ko rn=1 do. rn > 1 wale duplicates hain β€” delete karo. Intermediate mein jo self-join approach dekhi thi β€” yeh ROW_NUMBER approach zyada clean aur flexible hai (easily change kar sakte ho ki oldest rakhna hai ya latest, kaunse columns par partition karna hai).

Quick Revision β€” 30 Questions at a Glance

Q# Question Key Concept
1Window Functions?Calculate across rows WITHOUT collapsing β€” OVER()
2ROW_NUMBER()?Unique sequential number per partition
3ROW_NUMBER vs RANK vs DENSE_RANK?Ties: unique vs skip vs no-skip
4Nth highest salary?DENSE_RANK + CTE WHERE rnk = N
5NTILE()?Divide into N equal buckets
6PARTITION BY vs GROUP BY?PARTITION retains rows, GROUP collapses
7LAG() & LEAD()?Access previous/next row values
8Running Total?SUM() OVER(ORDER BY) β€” cumulative
9Moving Average?AVG() OVER(ROWS BETWEEN N PRECEDING)
10FIRST_VALUE / LAST_VALUE?First/last value in partition β€” frame matters!
11Window Frame?ROWS BETWEEN β€” defines calculation window
12CTE?WITH clause β€” named temporary result
13CTE vs Subquery vs Temp?CTE=readable, Subquery=simple, Temp=persistent
14Recursive CTE?Self-referencing β€” hierarchical data
15Generate series?Recursive CTE β€” numbers/dates
16Stored Procedure?Saved reusable SQL program β€” CALL to execute
17Procedure vs Function?Procedure=actions, Function=returns value in SELECT
18Trigger?Auto-fires on INSERT/UPDATE/DELETE
19Query Optimization?Indexes, avoid SELECT *, use EXISTS, LIMIT
20EXPLAIN?Shows execution plan β€” type, key, rows
21Normalization?1NF, 2NF, 3NF β€” reduce redundancy
22Denormalization?Intentional redundancy for read speed
23Top N per group?ROW_NUMBER + PARTITION BY + WHERE rn <= N
24YoY Growth SQL?LAG() for previous year comparison
25Consecutive days?Islands & Gaps β€” date minus ROW_NUMBER trick
26Find gaps?LEAD() β€” next value minus current > 1
27Pivot rows to columns?SUM(CASE WHEN) + GROUP BY
28Emp earning > manager?Self JOIN β€” e.salary > m.salary
29% of total?value / SUM() OVER() Γ— 100
30Delete duplicates (advanced)?ROW_NUMBER PARTITION BY dup_col β†’ DELETE rn > 1

πŸŽ‰ SQL Interview Questions β€” Complete!

3 blogs mein 90 SQL Interview Questions cover kiye β€” Basic (30), Intermediate (30), Advanced (30). Freshers se lekar 3+ years experience tak β€” saare levels covered. Previously available on Data Insights: MySQL Masterclass (7 Parts), Excel Masterclass (8 Parts), Power BI Masterclass (7 Parts), Pandas, NumPy, Matplotlib, Seaborn, Plotly, Data Cleaning + Statistics β€” sab FREE, detailed, Hinglish mein.

Happy Learning & Crack That Interview! πŸš€

πŸ‘€
Jatin Kumar
Data Analyst & Educator

Python, SQL, Power BI aur Excel mein practical tutorials likhta hoon β€” taaki data analytics seekhna aasan ho. Portfolio: jatinanalytics.co.in

Portfolio LinkedIn GitHub Kaggle All Articles
Share:

πŸ’¬ Comments (0)

Spam/links allowed nahi hain β€” respectful comments welcome!

Loading comments...

Was this article helpful?
Previous ArticleTop 30 Intermediate SQL Interview Questions And AnswersNext Article Power BI Basic Interview Questions

πŸ“š More Articles Like This

Top 30 Basic SQL Interview Questions Ans Answers

Read Article