Window functions · Cohorts · Joins · 2026

15 Advanced SQL Interview Questions

15 practical queries Amazon, Meta, Flipkart, Swiggy, Uber 15 min read

Data Analyst SQL rounds test how you turn a business metric (retention, churn, running totals, month-over-month change) into readable, fast SQL with CTEs and window functions. The first four questions come with a full query; the rest are a quick-fire round with the pattern to use.

Hard Retention & Cohorts Amazon Swiggy

1. Write a query to compute Month-1 (M+1) 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 (
  -- 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 (
  -- One row per user per active month
  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
),
WithPrevious AS (
  SELECT
    rev_month,
    total_revenue,
    LAG(total_revenue) OVER (ORDER BY rev_month) AS prev_revenue
  FROM MonthlyRevenue
)
SELECT
  rev_month,
  total_revenue,
  prev_revenue,
  ROUND(100.0 * (total_revenue - prev_revenue)
    / NULLIF(prev_revenue, 0), 2) AS mom_growth_pct
FROM WithPrevious
ORDER BY rev_month;
Hard DENSE_RANK Microsoft Uber

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

Business Problem:
Given employees(emp_id, emp_name, department_id, salary), list the three highest-paid employees in each department, keeping everyone who ties for a place.
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;
Quick-fire round: the pattern for questions 5 to 15
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:

SELECT
  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: keep the first copy of each row and delete the rest.

-- PostgreSQL: ctid is the physical row id
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: a recursive CTE that starts at the top of the tree and walks down one level at a time.

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;
For the call itself

The questions above are the prep. On the real call, ClapAssist helps with the ones you did not practice.

ClapAssist is an AI interview assistant for Mac and Windows. It listens to the interview on your computer and shows you what to say, in short lines you can read while you talk. Your live interview audio and screen are never stored. Your resume and notes are saved to your account so the app fills them in on any computer. It is hidden from screen share on every plan, including Free; only you can see it.

Download with 10 free minutes
Mac and Windows · Hidden from screen share on every plan, including Free · No card