Data Analyst Interview
Menu
Browse in your language. All mock interviews, preparation sessions and feedback are in English only.
📊 Data Analyst

SQL Window Functions Explained — RANK, LAG, LEAD, ROW_NUMBER with Real Examples (2026)

In brief: Practise SQL ranking and row comparisons with RANK, ROW_NUMBER, LAG and LEAD. Explain ordering, ties and partition boundaries when checking the result.
Quick Answer
SQL window functions calculate values across related rows without collapsing them like GROUP BY. They use OVER() with PARTITION BY (to group) and ORDER BY (to sort within the group). The most tested in interviews: RANK(), ROW_NUMBER(), LAG(), LEAD(), and SUM() OVER() for running totals.

Window functions calculate values across related rows while preserving each row. Practise ranking, comparing consecutive records, and running totals.

Practise interview-style exercises with worked explanations. These are learning examples, not a verified record of questions asked by a named employer.

What Are Window Functions?

Definition: A window function performs a calculation across a set of rows that are related to the current row — called a “window.” Unlike GROUP BY which collapses rows into one summary row per group, window functions return a value for every single row while still performing group-level calculations.

💡
The Key DifferenceGROUP BY: 10 departments → 10 summary rows. Window function: 10 departments with 50 employees → still 50 rows, but each row now has a department-level rank, running total, or comparison to previous row added as a new column.

The OVER() Clause — Core Syntax

FUNCTION() OVER (
    PARTITION BY column   -- divide into groups (optional)
    ORDER BY column        -- sort within each group
    ROWS BETWEEN ...       -- define frame (optional)
)

-- Example: rank employees by salary within each department
SELECT
    emp_name, department, salary,
    RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS salary_rank
FROM employees;

Ranking Functions — RANK, DENSE_RANK, ROW_NUMBER

FunctionHandles TiesOutput ExampleUse When
ROW_NUMBER()No — always unique1, 2, 3, 4, 5Need exactly 1 row per group
RANK()Same rank, skips next1, 1, 3, 4, 5Ties included, gaps acceptable
DENSE_RANK()Same rank, no skip1, 1, 2, 3, 4Ties included, no gaps wanted
-- Find the highest-paid employee in each department (exactly 1 per dept)
WITH ranked AS (
    SELECT
        emp_name, department, salary,
        ROW_NUMBER() OVER(PARTITION BY department ORDER BY salary DESC) AS rn
    FROM employees
)
SELECT emp_name, department, salary
FROM ranked WHERE rn = 1;

LAG and LEAD — Compare with Adjacent Rows

Definition: LAG() accesses a value from a previous row in the result set. LEAD() accesses a value from a subsequent row. Both are used for time-series comparisons — month-over-month growth, day-over-day changes, sequential analysis.

-- Month-over-month revenue growth
SELECT
    month,
    revenue,
    LAG(revenue, 1) OVER(ORDER BY month) AS prev_month_revenue,
    ROUND(
        (revenue - LAG(revenue, 1) OVER(ORDER BY month))
        * 100.0
        / LAG(revenue, 1) OVER(ORDER BY month),
        2
    ) AS mom_growth_pct
FROM monthly_revenue
ORDER BY month;

Running Totals and Moving Averages

SELECT
    order_date,
    daily_revenue,
    -- Running total (cumulative sum)
    SUM(daily_revenue) OVER(ORDER BY order_date) AS cumulative_revenue,
    -- 7-day moving average
    AVG(daily_revenue) OVER(
        ORDER BY order_date
        ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
    ) AS rolling_7d_avg
FROM daily_sales;

Top Window Function Interview Questions

  1. Find the top 2 customers by revenue in each city — ROW_NUMBER() OVER(PARTITION BY city ORDER BY revenue DESC), filter WHERE rn <= 2
  2. Calculate month-over-month revenue growth % — LAG() OVER(ORDER BY month), formula: (current – previous) * 100.0 / previous
  3. Compute a 7-day rolling average of daily active users — AVG() OVER(ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW)
  4. Find users active on 3+ consecutive days — ROW_NUMBER trick: date – ROW_NUMBER() creates a group key for consecutive dates
  5. Find the percentage each salesperson contributes to total sales — SUM(sales) / SUM(SUM(sales)) OVER() * 100
⚠️
Critical Interview RuleUse ROW_NUMBER when you need exactly 1 row per group (strict top-1). Use RANK when ties should both appear. Getting this wrong is one of the most common window function interview mistakes. Always ask: “If two employees have the same salary, should both appear in the result?”

⭐ Key Takeaways

  • Window functions add a calculated column to every row — they do NOT reduce rows like GROUP BY
  • OVER() defines the window: PARTITION BY = groups, ORDER BY = sort within group
  • ROW_NUMBER = unique always. RANK = ties same, skips next. DENSE_RANK = ties same, no skip
  • LAG/LEAD access previous/next row values — essential for time-series and growth calculations
  • SUM OVER ORDER BY = running total. AVG with ROWS BETWEEN = moving average
  • Practise window functions for ranking, comparisons, and running calculations.
❓ Frequently Asked Questions
What are SQL window functions?
+
SQL window functions calculate values across related rows without collapsing them like GROUP BY. They add a new calculated column to each existing row. They use the OVER() clause to define the “window” — the set of rows to calculate across. Common examples: RANK() OVER(ORDER BY salary DESC) adds a salary rank to every employee row without reducing the number of rows.
What is the difference between RANK and DENSE_RANK?
+
RANK() assigns the same rank to tied values but skips the next number — example: 1, 1, 3, 4, 5. DENSE_RANK() assigns the same rank to tied values without skipping — example: 1, 1, 2, 3, 4. Use DENSE_RANK when you want to show “2nd highest” even if there are ties at position 1. Use RANK when the rank should reflect the actual position in an ordered list.
How do I use LAG() in SQL for month-over-month growth?
+
LAG(column, offset) OVER(ORDER BY date_column) gives the value from N rows back. For month-over-month growth: SELECT month, revenue, LAG(revenue, 1) OVER(ORDER BY month) AS prev_revenue, ROUND((revenue – LAG(revenue,1) OVER(ORDER BY month)) * 100.0 / LAG(revenue,1) OVER(ORDER BY month), 2) AS mom_pct FROM monthly_data. The first month will have NULL for prev_revenue since there is no previous month.
What is PARTITION BY in SQL window functions?
+
PARTITION BY divides the result set into groups (partitions) before the window function is applied. RANK() OVER(ORDER BY salary DESC) ranks all employees together globally. RANK() OVER(PARTITION BY department ORDER BY salary DESC) ranks employees separately within each department — resetting the rank counter for each department. PARTITION BY is optional — without it, the entire result set is one window.

Practice Window Functions with Live SQL Compiler

Our SQL Hub has a live SQL compiler — practice RANK, LAG, LEAD and running totals right in your browser. No setup needed.

Window Functions Full Guide + Compiler →
PS
Prakhar Shrivastava
Prakhar Shrivastava · Founder, Data Analyst Interview
Author of the SQL, Python and interview-practice guides on this site. Helping India’s data analysts crack window function questions — the hardest and most tested SQL topic in 2026.

Documentation and next steps

Check the relevant documentation for your software version and database dialect. These are practice resources, not verified employer question banks.

Find a related learning guide · About the author · Suggest a correction

Leave a Reply

Discover more from Data Analyst Interview

Subscribe now to keep reading and get access to the full archive.

Continue reading

WhatsApp