0
0
PostgreSQLquery~7 mins

Window frame (ROWS BETWEEN, RANGE BETWEEN) in PostgreSQL

Choose your learning style9 modes available
Introduction

Window frames let you control which rows are included when calculating values over a group of rows. This helps you get running totals, moving averages, and other calculations that depend on nearby rows.

When you want to calculate a running total of sales over time.
When you need to find the average score of the last 3 tests for each student.
When you want to compare each row's value to the previous or next rows in a sorted list.
When you want to calculate a cumulative sum but only within a certain range of rows.
When you want to create rankings or percentiles that consider a specific window of data.
Syntax
PostgreSQL
window_function() OVER (PARTITION BY column ORDER BY column ROWS BETWEEN frame_start AND frame_end)

window_function() OVER (PARTITION BY column ORDER BY column RANGE BETWEEN frame_start AND frame_end)

ROWS BETWEEN counts rows exactly before or after the current row.

RANGE BETWEEN considers values in the ORDER BY column and includes rows with values in a range around the current row's value.

Examples
This sums sales for the current row and the two rows before it, based on date order.
PostgreSQL
SUM(sales) OVER (ORDER BY date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW)
This calculates the average score for tests taken in the last 7 days up to the current test date for each student.
PostgreSQL
AVG(score) OVER (PARTITION BY student_id ORDER BY test_date RANGE BETWEEN INTERVAL '7 days' PRECEDING AND CURRENT ROW)
This counts all rows with salary less than or equal to the current row's salary.
PostgreSQL
COUNT(*) OVER (ORDER BY salary RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
Sample Program

This example creates a sales table and inserts 5 days of sales. It then calculates two running sums:

  • running_sum_rows: sums the current and two previous rows by date.
  • running_sum_range: sums amounts for sales within 2 days before the current sale date.
PostgreSQL
CREATE TABLE sales_data (
  id SERIAL PRIMARY KEY,
  sale_date DATE,
  amount INT
);

INSERT INTO sales_data (sale_date, amount) VALUES
('2024-01-01', 100),
('2024-01-02', 200),
('2024-01-03', 300),
('2024-01-04', 400),
('2024-01-05', 500);

SELECT
  sale_date,
  amount,
  SUM(amount) OVER (ORDER BY sale_date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS running_sum_rows,
  SUM(amount) OVER (ORDER BY sale_date RANGE BETWEEN INTERVAL '2 days' PRECEDING AND CURRENT ROW) AS running_sum_range
FROM sales_data
ORDER BY sale_date;
OutputSuccess
Important Notes

Use ROWS when you want to count a fixed number of rows before or after the current row.

Use RANGE when you want to include rows based on the value range in the ORDER BY column, which can include multiple rows with the same value.

Be careful: RANGE requires the ORDER BY column to be numeric, date, or interval type for meaningful ranges.

Summary

Window frames control which rows are included in window function calculations.

ROWS BETWEEN counts rows by position relative to the current row.

RANGE BETWEEN counts rows by value range in the ORDER BY column.