Introduction
A window function is a special type of function that allows you to perform calculations on a specific subset, or "window," of rows from a result set. It's like looking at a window into your data and performing calculations on that smaller portion. Window functions are different from regular aggregate functions like SUM or AVG because they calculate values for each row individually, taking into account the rows within the defined window. They can be used to perform various calculations, such as aggregations, ranking, and statistical operations, without the need for grouping the data or using subqueries.
There are several types of window functions commonly used in SQL. Here are some of the most frequently used ones:
Aggregate Window Functions
These functions perform calculations on a subset of rows within a window and return a single aggregated result.
SUM(): Calculates the sum of a column within the window.
//Calculate the total revenue for each region, including a column with the overall average revenue.
SELECT
region,
SUM(revenue) AS total_revenue,
AVG(revenue) OVER () AS overall_avg_revenue
FROM
sales
GROUP BY
region;
AVG(): Computes the average of a column within the window.
SELECT
product_id,
product_name,
category,
price,
AVG(price) OVER (PARTITION BY category) AS avg_price
FROM
products;
COUNT(): Counts the number of rows within the window.
SELECT
product_id,
product_name,
category,
price,
COUNT(*) OVER (PARTITION BY category) AS category_count
FROM
products;
MAX(): Finds the maximum value within the window.
SELECT
product_id,
product_name,
category,
price,
MAX(price) OVER (PARTITION BY category) AS max_price
FROM
products;
MIN(): Finds the minimum value within the window.
SELECT
emp_id,
emp_name,
department,
salary,
MIN(salary) OVER (PARTITION BY department) AS min_salary
FROM
employees;
Ranking Window Functions
These functions assign a rank or position to each row within a window based on a specified criterion.
ROW_NUMBER(): Assigns a unique number to each row within the window.
SELECT
ROW_NUMBER() OVER (ORDER BY department) AS row_num,
employee_id,
employee_name,
department,
salary
FROM
employee
ORDER BY
department;
RANK(): Assigns a rank to each row, with gaps in case of ties.
SELECT
RANK() OVER (ORDER BY price DESC) AS product_rank,
product_id,
product_name,
category,
price
FROM
products;
DENSE_RANK(): Assigns a rank to each row without gaps in case of ties.
SELECT
sale_id,
product_name,
category,
sale_amount,
DENSE_RANK() OVER (ORDER BY sale_amount DESC) AS dense_rank
FROM
sales;
NTILE(): Divides the rows into specified buckets or percentiles.
SELECT
student_id,
student_name,
score,
NTILE(3) OVER (ORDER BY score DESC) AS tile_number
FROM
students;
Analytic Window Functions
These functions provide additional analytical capabilities and often require both partitioning and ordering of rows.
LAG(): Retrieves the value from a previous row within the window.
SELECT
order_id,
customer_id,
order_date,
order_total,
LAG(order_total, 1, 0) OVER (PARTITION BY customer_id ORDER BY order_date) AS previous_order_total
FROM
orders;
LEAD(): Retrieves the value from a subsequent row within the window.
SELECT
employee_id,
first_name,
last_name,
department,
salary,
LEAD(salary, 1, 0) OVER (PARTITION BY department ORDER BY employee_id) AS next_salary
FROM
employees;
FIRST_VALUE(): Returns the value of a specified expression from the first row in the window.
SELECT
employee_id,
first_name,
last_name,
department,
salary,
FIRST_VALUE(salary) OVER (PARTITION BY department ORDER BY employee_id) AS first_salary
FROM
employees;
LAST_VALUE(): Returns the value of a specified expression from the last row in the window.
SELECT
employee_id,
first_name,
last_name,
department,
salary,
LAST_VALUE(salary) OVER (PARTITION BY department ORDER BY employee_id
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS last_salary
FROM
employees;
Here are some examples that aim to provide valuable insights and enhance your understanding of Window functions effectively
Calculate the total revenue for each region, including a column with the overall average revenue.
SELECT
region,
SUM(revenue) AS total_revenue,
AVG(revenue) OVER () AS overall_avg_revenue
FROM
sales
GROUP BY
region;
Rank products based on their sales quantities within each category.
SELECT
category,
product,
sales_quantity,
RANK() OVER (PARTITION BY category ORDER BY sales_quantity DESC) AS product_rank
FROM
sales
ORDER BY
category, product_rank;
Calculate the running total of sales revenue for each day.
SELECT
sales_date,
SUM(revenue) OVER (ORDER BY sales_date) AS running_total
FROM
daily_sales
ORDER BY
sales_date;
Determine the percentage of total sales revenue contributed by each product within its category.
SELECT
category,
product,
revenue,
revenue / SUM(revenue) OVER (PARTITION BY category) * 100 AS revenue_percentage
FROM
sales
ORDER BY
category, product;
Find the highest revenue achieved in each quarter.
SELECT
DATE_TRUNC('quarter', sales_date) AS quarter,
MAX(revenue) AS highest_revenue
FROM
sales
GROUP BY
quarter
ORDER BY
quarter;
Calculate the average rating of movies within each genre.
SELECT
genre,
AVG(rating) AS average_rating
FROM
movies
GROUP BY
genre;
Determine the difference in sales quantity between the current row and the previous row.
SELECT
order_date,
sales_quantity,
LAG(sales_quantity) OVER (ORDER BY order_date) AS previous_sales_quantity,
sales_quantity - LAG(sales_quantity) OVER (ORDER BY order_date) AS sales_quantity_difference
FROM
sales;
Rank customers based on their total purchase amounts.
SELECT
customer_id,
total_purchase_amount,
RANK() OVER (ORDER BY total_purchase_amount DESC) AS purchase_rank
FROM
(
SELECT
customer_id,
SUM(purchase_amount) AS total_purchase_amount
FROM
purchases
GROUP BY
customer_id
) AS purchase_summary;

Join the conversation! Your thoughts help the community grow.