AskDB
·8 min read

SQL Window Functions: A Practical Guide

Window functions perform calculations across a set of rows related to the current row without collapsing them. They are essential for ranking, running totals, and comparing rows.

Syntax

function_name() OVER (
  [PARTITION BY column]
  [ORDER BY column [ASC|DESC]]
  [ROWS BETWEEN ...]
)

ROW_NUMBER, RANK, DENSE_RANK

SELECT name, department, salary,
  ROW_NUMBER() OVER (ORDER BY salary DESC) as row_num,
  RANK() OVER (ORDER BY salary DESC) as rank,
  DENSE_RANK() OVER (ORDER BY salary DESC) as dense_rank
FROM employees;
  • ROW_NUMBER — unique sequential number (1, 2, 3, 4)
  • RANK — same rank for ties, skips numbers (1, 2, 2, 4)
  • DENSE_RANK — same rank for ties, no skip (1, 2, 2, 3)

LAG and LEAD

Access values from previous or next rows.

SELECT month, revenue,
  LAG(revenue) OVER (ORDER BY month) as prev_month,
  revenue - LAG(revenue) OVER (ORDER BY month) as growth
FROM monthly_sales;

Running Totals with SUM OVER

SELECT date, amount,
  SUM(amount) OVER (ORDER BY date) as running_total
FROM transactions;

Partitioned Rankings

Rank within groups using PARTITION BY.

SELECT name, department, salary,
  RANK() OVER (PARTITION BY department ORDER BY salary DESC) as dept_rank
FROM employees;

This ranks employees within each department separately.

NTILE — Dividing Rows into Buckets

SELECT name, salary,
  NTILE(4) OVER (ORDER BY salary DESC) as quartile
FROM employees;

Divides employees into 4 groups by salary (top 25%, 25-50%, etc.).

Window Functions vs GROUP BY

  • GROUP BY collapses rows — one output row per group
  • Window functions keep all rows — calculation added as a new column

Practice

Format your window function queries with the SQL Formatter for better readability. Complex OVER clauses are much easier to review when properly indented.