A Beginner’s Guide to SQL Window Functions with Practical Examples

Learn the basics of SQL window functions with easy-to-understand explanations and practical examples to enhance your data analysis skills.

SQL window functions are powerful tools that allow you to perform calculations across a set of table rows related to the current row without grouping the data. These functions are useful for tasks like running totals, ranking, moving averages, and more. This beginner-friendly guide will introduce you to some common window functions with practical SQL examples.

Unlike aggregate functions that collapse multiple rows into a single result, window functions perform calculations across a 'window' of rows while retaining the individual row details.

Let’s start with a simple example. Suppose we have a sales table with columns: salesperson, sale_date, and amount.

sql
CREATE TABLE sales (
  salesperson VARCHAR(50),
  sale_date DATE,
  amount INT
);

INSERT INTO sales (salesperson, sale_date, amount) VALUES
('Alice', '2024-01-01', 100),
('Alice', '2024-01-02', 150),
('Bob', '2024-01-01', 200),
('Bob', '2024-01-03', 50),
('Alice', '2024-01-03', 200);

### Example 1: Using ROW_NUMBER() to Assign Unique Row Numbers ROW_NUMBER() assigns a unique number to each row within the partition of a result set, ordered by specified columns.

sql
SELECT
  salesperson,
  sale_date,
  amount,
  ROW_NUMBER() OVER (PARTITION BY salesperson ORDER BY sale_date) AS sale_rank
FROM sales;

This query assigns a "sale_rank" to each sale by the salesperson, ordered by the sale_date.

### Example 2: Calculating Running Total with SUM() OVER() You can compute a cumulative sum of sales amounts for each salesperson ordered by date.

sql
SELECT
  salesperson,
  sale_date,
  amount,
  SUM(amount) OVER (PARTITION BY salesperson ORDER BY sale_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS running_total
FROM sales;

The running_total column shows the cumulative sum of sales amounts up to the current sale for each salesperson.

### Example 3: Using RANK() to Show Tied Rankings RANK() works similar to ROW_NUMBER() but assigns the same rank to identical values with gaps in ranking numbers.

sql
SELECT
  salesperson,
  sale_date,
  amount,
  RANK() OVER (PARTITION BY salesperson ORDER BY amount DESC) AS amount_rank
FROM sales;

This query ranks each sale by amount in descending order for each salesperson. Sales with the same amount get the same rank.

### Example 4: Getting Previous Row Value with LAG() LAG() lets you access previous rows without using self-joins.

sql
SELECT
  salesperson,
  sale_date,
  amount,
  LAG(amount, 1, 0) OVER (PARTITION BY salesperson ORDER BY sale_date) AS previous_amount
FROM sales;

Here, previous_amount shows the amount from the previous sale of the same salesperson, or 0 if there is no previous sale.

### Wrap-Up Window functions greatly enhance SQL's ability to perform complex calculations while preserving row-level detail. Practice using ROW_NUMBER(), RANK(), SUM() OVER(), and LAG() to better analyze your data.