Window Functions
Advanced analytics without losing row detail
Window functions perform calculations across rows related to the current row, without collapsing them into groups. They're powerful for rankings, running totals, and comparisons.
Basic Syntax
FUNCTION() OVER (
PARTITION BY column -- Optional: divide into groups
ORDER BY column -- Optional: order within partition
)ROW_NUMBER
-- Number each row
SELECT
name,
total,
ROW_NUMBER() OVER (ORDER BY total DESC) AS rank
FROM orders;
-- Number within each customer
SELECT
user_id,
total,
ROW_NUMBER() OVER (
PARTITION BY user_id
ORDER BY created_at DESC
) AS order_num
FROM orders;
-- Get most recent order per user
SELECT * FROM (
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY user_id
ORDER BY created_at DESC
) AS rn
FROM orders
) WHERE rn = 1;Ranking Functions
-- Compare ranking functions
SELECT
name,
score,
ROW_NUMBER() OVER (ORDER BY score DESC) AS row_num, -- 1,2,3,4
RANK() OVER (ORDER BY score DESC) AS rank, -- 1,2,2,4 (gaps)
DENSE_RANK() OVER (ORDER BY score DESC) AS dense -- 1,2,2,3 (no gaps)
FROM players;Running Totals
-- Running total of orders
SELECT
created_at,
total,
SUM(total) OVER (ORDER BY created_at) AS running_total
FROM orders;
-- Running total per customer
SELECT
user_id,
created_at,
total,
SUM(total) OVER (
PARTITION BY user_id
ORDER BY created_at
) AS customer_running_total
FROM orders;LAG and LEAD
-- Compare to previous row
SELECT
month,
revenue,
LAG(revenue) OVER (ORDER BY month) AS prev_month,
revenue - LAG(revenue) OVER (ORDER BY month) AS change
FROM monthly_sales;
-- Compare to next row
SELECT
name,
score,
LEAD(score) OVER (ORDER BY score DESC) AS next_lower_score
FROM players;Note: Window functions are supported in SQLite 3.25+, PostgreSQL, MySQL 8+, and SQL Server.