MySQL Window Functions allow performing calculations across a set of rows related to the current row without collapsing results (unlike GROUP BY). They are ideal for ranking, running totals, lead/lag comparisons and more.
OVER().
-- Window function general syntax
function_name() OVER (
[PARTITION BY column_name]
[ORDER BY column_name]
[ROWS or RANGE clause]
)
ROW_NUMBER() — unique row number within partition.RANK() / DENSE_RANK() — ranking functions (with or without gaps).LAG(col, offset) / LEAD(col, offset) — access neighboring row values.OVER() (e.g., SUM(), AVG()) for running totals etc.
-- Create sample sales table
CREATE TABLE sales (
id INT AUTO_INCREMENT PRIMARY KEY,
salesperson VARCHAR(50),
amount DECIMAL(10,2)
);
-- Insert sample rows
INSERT INTO sales (salesperson, amount) VALUES
('Alice', 500),
('Bob', 700),
('Alice', 300),
('Bob', 400),
('Charlie', 800);
-- ROW_NUMBER() per salesperson ordered by amount descending
SELECT salesperson, amount,
ROW_NUMBER() OVER (PARTITION BY salesperson ORDER BY amount DESC) AS row_num
FROM sales;
-- Running total per salesperson ordered by id
SELECT salesperson, amount,
SUM(amount) OVER (PARTITION BY salesperson ORDER BY id) AS running_total
FROM sales;
-- LAG() and LEAD() to access previous and next sale
SELECT salesperson, amount,
LAG(amount, 1) OVER (PARTITION BY salesperson ORDER BY id) AS prev_sale,
LEAD(amount, 1) OVER (PARTITION BY salesperson ORDER BY id) AS next_sale
FROM sales;
Click the buttons below to see how different functions change the result.
| ID | Salesperson | Amount | Result |
|---|
ROW_NUMBER() will assign sequential numbers within each salesperson's partition. SUM() OVER (...) produces a cumulative sum for each partition (running totals). LAG() and LEAD() return previous/next values (useful for comparisons).
Unlike aggregation with GROUP BY, window functions keep every original row and add computed columns alongside them.
ORDER BY inside the window if the operation depends on row order (ranking, running totals).ROW_NUMBER() for deduplication and pagination when combined with a partition.LAG()/LEAD() over self-joins for adjacent-row calculations — simpler and faster.GROUP BY — when both are needed, use subqueries.name, department, and salary.RANK() and DENSE_RANK() to compute department-wise salary ranks.LAG() and LEAD().SUM() OVER (PARTITION BY department ORDER BY id).