Window Functions • Cohorts • Joins • 2026 Updated

15 Advanced SQL Interview Questions

📊 15 practical queries 🏢 Amazon, Meta, Flipkart, Swiggy, Uber ⏱️ 15 min read

In modern Data Analyst interviews, syntax questions are obsolete. Top tech companies evaluate how you translate ambiguous business metrics (retention, churn, attribution, running MoM changes) into readable, performant SQL using CTEs and Window Functions.

Hard Retention & Cohorts Amazon Swiggy

1. Write a query to compute 30-Day User Retention Cohorts

Business Problem:
Given a table `user_logins(user_id, login_date)`, find what percentage of users who joined in each calendar month came back and logged in the following month (M+1).
WITH UserFirstLogin AS (
  -- Find each user's first login month
  SELECT user_id,
         DATE_TRUNC('month', MIN(login_date)) AS cohort_month
  FROM user_logins
  GROUP BY user_id
),
MonthlyLogins AS (
  -- Get unique user login months
  SELECT DISTINCT user_id,
         DATE_TRUNC('month', login_date) AS active_month
  FROM user_logins
)
SELECT
  f.cohort_month,
  COUNT(DISTINCT f.user_id) AS cohort_size,
  COUNT(DISTINCT CASE WHEN m.active_month = f.cohort_month + INTERVAL '1 month' THEN m.user_id END) AS retained_m1,
  ROUND(100.0 * COUNT(DISTINCT CASE WHEN m.active_month = f.cohort_month + INTERVAL '1 month' THEN m.user_id END) / COUNT(DISTINCT f.user_id), 2) AS m1_retention_rate
FROM UserFirstLogin f
LEFT JOIN MonthlyLogins m ON f.user_id = m.user_id
GROUP BY f.cohort_month
ORDER BY f.cohort_month;
Why Interviewers Love This Answer:

It avoids messy subqueries by using modular CTEs. It handles edge cases like users who didn't log in during M+1 cleanly using `LEFT JOIN` and conditional aggregation (`COUNT(DISTINCT CASE ...)`).

Medium Window Functions Google Meta

2. Calculate Month-over-Month (MoM) Revenue Growth Rate

Business Problem:
Given `orders(order_id, order_date, amount)`, calculate total revenue per month and the percentage growth compared to the previous month.
WITH MonthlyRevenue AS (
  SELECT
    DATE_TRUNC('month', order_date) AS rev_month,
    SUM(amount) AS total_revenue
  FROM orders
  GROUP BY 1
)
SELECT
  rev_month,
  total_revenue,
  LAG(total_revenue, 1) OVER (ORDER BY rev_month) AS prev_month_revenue,
  ROUND(100.0 * (total_revenue - LAG(total_revenue, 1) OVER (ORDER BY rev_month)) / LAG(total_revenue, 1) OVER (ORDER BY rev_month), 2) AS mom_growth_pct
FROM MonthlyRevenue
ORDER BY rev_month;
Hard DENSE_RANK Microsoft Uber

3. Find the Top 3 Highest Earning Employees per Department (Handling Ties)

WITH RankedEmployees AS (
  SELECT
    emp_id,
    emp_name,
    department_id,
    salary,
    DENSE_RANK() OVER (
      PARTITION BY department_id 
      ORDER BY salary DESC
    ) AS salary_rank
  FROM employees
)
SELECT department_id, emp_id, emp_name, salary, salary_rank
FROM RankedEmployees
WHERE salary_rank <= 3
ORDER BY department_id, salary_rank;
Hard Gaps and Islands Netflix LinkedIn

4. Detect Consecutive Login Streaks (The Gaps & Islands Problem)

Business Problem:
Find users who logged in for 5 or more consecutive days without interruption.
WITH DistinctDays AS (
  SELECT DISTINCT user_id, DATE(login_date) AS login_day
  FROM user_logins
),
GroupedLogins AS (
  SELECT
    user_id,
    login_day,
    login_day - (ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_day)) * INTERVAL '1 day' AS streak_group
  FROM DistinctDays
)
SELECT
  user_id,
  MIN(login_day) AS streak_start,
  MAX(login_day) AS streak_end,
  COUNT(*) AS consecutive_days
FROM GroupedLogins
GROUP BY user_id, streak_group
HAVING COUNT(*) >= 5;
MediumRunning Totals

5. Calculate Cumulative Running Total of Orders per Customer

Query Pattern: SELECT customer_id, order_date, amount, SUM(amount) OVER (PARTITION BY customer_id ORDER BY order_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as running_spend FROM orders;

MediumChurn

6. Identify Churned Users (Active Last Month, Zero Activity This Month)

Query Pattern: Use a LEFT JOIN on user IDs between Last Month's active cohort and This Month's active cohort, filtering with WHERE this_month.user_id IS NULL.

MediumRolling Averages

7. Compute a 7-Day Moving Average of Daily Transactions

Query Pattern: AVG(daily_sales) OVER (ORDER BY sales_date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS moving_avg_7d.

MediumAggregations

8. Pivot Data in SQL (Rows to Columns without PIVOT operator)

Solution: Use conditional aggregation: SUM(CASE WHEN quarter = 'Q1' THEN revenue ELSE 0 END) AS Q1_rev across desired dimensions.

HardSessionization

9. Sessionize User Clickstream with 30-Minute Inactivity Windows

Method: Use LAG(click_time) OVER (PARTITION BY user_id ORDER BY click_time) to find idle time. If click_time - prev_time > 30 min, flag as 1, otherwise 0. Take running SUM(flag) to assign session IDs.

MediumPerformance

10. Why is WHERE x != 'val' slow and how do you optimize it?

Explanation: Negative operators (!=, NOT IN) prevent database query planners from using B-Tree indexes, triggering full table scans. Optimize by restructuring to positive filters, using partial indexes, or bitmap scans.

MediumNULL Handling

11. Why does `WHERE col NOT IN (SELECT other_col FROM table)` return 0 rows?

The Trap: If the subquery contains even a single NULL, the NOT IN evaluates to UNKNOWN for every row, returning an empty result set. Always use NOT EXISTS or filter WHERE other_col IS NOT NULL.

MediumSelf-Joins

12. Find Employees Who Earn More Than Their Direct Manager

Query: SELECT e.emp_name FROM employees e JOIN employees m ON e.manager_id = m.emp_id WHERE e.salary > m.salary;

HardPercentiles

13. Calculate Median & 95th Percentile Order Value

Query Pattern: PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY amount) AS median, PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY amount) AS p95 FROM orders;

MediumData Quality

14. Find Duplicate Records Without a Primary Key

Query: WITH Dupes AS (SELECT ctid, ROW_NUMBER() OVER (PARTITION BY col1, col2, col3 ORDER BY ctid) as r FROM my_table) DELETE FROM my_table WHERE ctid IN (SELECT ctid FROM Dupes WHERE r > 1);

MediumCTEs

15. Recursive CTE: Find Complete Organizational Hierarchy Tree

Solution: Use WITH RECURSIVE OrgTree AS (SELECT emp_id, emp_name, manager_id, 1 as lvl FROM employees WHERE manager_id IS NULL UNION ALL SELECT e.emp_id, e.emp_name, e.manager_id, o.lvl + 1 FROM employees e JOIN OrgTree o ON e.manager_id = o.emp_id) SELECT * FROM OrgTree;

Undetectable AI for live interviews

Crack any interview, no matter how tough

Live SQL coding rounds test query syntax under strict time limits. When you're sharing your screen on CoderPad or Google Docs, you can't open extra browser tabs.

ClapAssist is your silent co-pilot. Runs directly on your Mac or Windows desktop, excluded at the OS level from screen sharing, giving you instant SQL syntax, window functions, and business explanations in under a second.

Download ClapAssist with 10 Free Minutes →
Mac & Windows · Works with Google Meet, Zoom & Teams · Pay once, no subscription