0
0
SQLquery~15 mins

Window frame specification (ROWS BETWEEN) in SQL - Deep Dive

Choose your learning style9 modes available
Overview - Window frame specification (ROWS BETWEEN)
What is it?
Window frame specification with ROWS BETWEEN defines which rows around the current row are included in a window function calculation. It lets you control the exact range of rows to consider, based on their position relative to the current row. This helps perform calculations like running totals or moving averages over a specific set of rows. It is part of SQL's window functions that work on a set of rows without collapsing the result into fewer rows.
Why it matters
Without window frame specification, window functions would always consider all rows in the partition, which limits flexibility. ROWS BETWEEN lets you focus calculations on a moving window of rows, enabling powerful analytics like trends, rankings, and comparisons over time or sequences. Without it, you would need complex self-joins or subqueries, which are slower and harder to write.
Where it fits
Learners should first understand basic SQL SELECT queries and aggregate functions. Then they should learn window functions and PARTITION BY and ORDER BY clauses. After mastering ROWS BETWEEN, they can explore advanced window functions and performance tuning.
Mental Model
Core Idea
ROWS BETWEEN defines a sliding window of rows around the current row to precisely control which rows a window function uses for its calculation.
Think of it like...
Imagine you are looking through a moving window on a train, and you only see a few houses before and after your current position. The window frame tells you exactly which houses you can see and count as you move along the track.
Current row: [X]
Window frame: [X-2, X-1, X, X+1, X+2]

Example:
Row positions: 1  2  3  4  5  6  7
Window frame for row 4: rows 2 to 6

┌─────────────┐
│ 2 3 [4] 5 6 │ <- rows included in frame
└─────────────┘
Build-Up - 7 Steps
1
FoundationUnderstanding window functions basics
🤔
Concept: Window functions perform calculations across a set of rows related to the current row without collapsing the result.
A window function like ROW_NUMBER() assigns a number to each row based on order but keeps all rows visible. It uses PARTITION BY to group rows and ORDER BY to sort them within each group.
Result
You get a new column with row numbers for each partition, but all original rows remain.
Understanding that window functions keep all rows and add calculations helps grasp why controlling the frame matters.
2
FoundationWhat is a window frame in SQL?
🤔
Concept: A window frame defines the subset of rows around the current row that a window function uses for its calculation.
By default, some window functions consider all rows in the partition. The frame lets you limit this to a smaller range, like the current row and the two before it.
Result
You can calculate things like running totals or moving averages over just a few rows instead of the whole partition.
Knowing that the frame controls the calculation range is key to customizing window function behavior.
3
IntermediateROWS BETWEEN syntax and options
🤔Before reading on: do you think ROWS BETWEEN can specify rows before and after the current row independently? Commit to yes or no.
Concept: ROWS BETWEEN lets you specify a start and end point relative to the current row, using keywords like UNBOUNDED PRECEDING, CURRENT ROW, and N PRECEDING/FOLLOWING.
Syntax example: ROWS BETWEEN 2 PRECEDING AND 1 FOLLOWING means include 2 rows before and 1 row after the current row. You can also use: - UNBOUNDED PRECEDING: from the first row in the partition - UNBOUNDED FOLLOWING: to the last row in the partition - CURRENT ROW: the current row itself
Result
You get a flexible window frame that can slide and vary in size depending on the current row's position.
Understanding the syntax lets you precisely control the window size and direction for calculations.
4
IntermediateDifference between ROWS and RANGE frames
🤔Before reading on: do you think ROWS and RANGE frame types always behave the same? Commit to yes or no.
Concept: ROWS counts physical rows relative to the current row, while RANGE considers logical values in the ORDER BY column, including ties.
ROWS BETWEEN 1 PRECEDING AND CURRENT ROW includes exactly one row before and the current row. RANGE BETWEEN 1 PRECEDING AND CURRENT ROW includes all rows with ORDER BY values within 1 unit before the current row's value. This means RANGE can include multiple rows if they have the same ORDER BY value.
Result
ROWS gives a fixed number of rows; RANGE can include variable rows based on values.
Knowing this difference prevents bugs when your data has duplicates or you want value-based windows.
5
IntermediateUsing ROWS BETWEEN for running totals
🤔
Concept: You can calculate a running total by summing all rows from the start of the partition up to the current row using ROWS BETWEEN.
Example: SUM(sales) OVER (ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) This sums sales from the first date up to the current date for each row.
Result
Each row shows the total sales so far, growing as you move down the rows.
Applying ROWS BETWEEN for cumulative sums is a common and powerful use case.
6
AdvancedHandling frame boundaries at partition edges
🤔Before reading on: do you think ROWS BETWEEN can reference rows that don't exist (like before the first row)? Commit to yes or no.
Concept: When the frame references rows outside the partition (like 2 preceding rows for the first row), SQL automatically adjusts the frame to available rows only.
If you say ROWS BETWEEN 2 PRECEDING AND CURRENT ROW for the first row, it only includes the first row itself because no preceding rows exist. This prevents errors and keeps calculations consistent.
Result
Window functions gracefully handle edges without failing or returning NULL unexpectedly.
Understanding automatic frame adjustment helps avoid confusion about missing data at edges.
7
ExpertPerformance implications of window frames
🤔Before reading on: do you think smaller window frames always improve query speed? Commit to yes or no.
Concept: Window frame size affects how much data the database processes for each row, impacting performance. Smaller frames can be faster but not always.
Databases optimize window functions differently. Some cache results or use indexes. Large frames or complex ORDER BY can slow queries. Choosing the right frame balances accuracy and speed. Example: Using ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW for a large partition can be slower than a fixed small frame.
Result
Understanding performance helps write efficient queries and avoid slow reports.
Knowing how frame size impacts execution guides better query design in production.
Under the Hood
Internally, the database engine processes window functions by scanning rows in the partition ordered as specified. The ROWS BETWEEN frame tells the engine which rows to include for each current row's calculation by counting physical row positions. The engine dynamically adjusts the frame boundaries for each row, efficiently reusing computations when possible to avoid recalculating over the entire partition every time.
Why designed this way?
The ROWS BETWEEN syntax was designed to give precise control over the window size and direction, enabling a wide range of analytics. It balances expressiveness and performance by letting users specify exact row ranges. Alternatives like RANGE were added later to handle value-based frames, but ROWS remains fundamental for position-based calculations.
Partition rows ordered by key:

┌─────────────┐
│ Row 1       │
│ Row 2       │
│ Row 3       │
│ Row 4 (cur) │
│ Row 5       │
│ Row 6       │
└─────────────┘

For each current row:
  ┌─────────────────────────────┐
  │ Calculate using rows from   │
  │ start_frame to end_frame    │
  └─────────────────────────────┘

Frame moves as current row moves.
Myth Busters - 4 Common Misconceptions
Quick: Does ROWS BETWEEN always include the current row? Commit yes or no.
Common Belief:ROWS BETWEEN always includes the current row by default.
Tap to reveal reality
Reality:ROWS BETWEEN requires explicit frame boundaries; if you specify a frame that excludes the current row, it won't be included.
Why it matters:Assuming the current row is always included can cause wrong calculations, like missing the current row's value in sums.
Quick: Does ROWS BETWEEN consider the values in ORDER BY or just row positions? Commit your answer.
Common Belief:ROWS BETWEEN frames rows based on ORDER BY values, including all rows with similar values.
Tap to reveal reality
Reality:ROWS BETWEEN counts physical row positions, ignoring ORDER BY values; it does not group ties automatically.
Why it matters:Confusing ROWS with RANGE can lead to unexpected frame sizes and incorrect results when data has duplicates.
Quick: Can ROWS BETWEEN reference rows outside the partition? Commit yes or no.
Common Belief:ROWS BETWEEN can cause errors if frame boundaries go beyond partition edges.
Tap to reveal reality
Reality:SQL automatically adjusts frame boundaries to available rows, preventing errors at edges.
Why it matters:Expecting errors can make learners add unnecessary checks or avoid useful frames.
Quick: Does a smaller ROWS BETWEEN frame always mean faster queries? Commit yes or no.
Common Belief:Smaller frames always improve query performance.
Tap to reveal reality
Reality:Performance depends on many factors; sometimes smaller frames add overhead due to repeated calculations or lack of optimization.
Why it matters:Assuming smaller frames are always better can lead to inefficient query designs.
Expert Zone
1
Some databases optimize window frames by caching partial aggregates, but this depends on frame type and function used.
2
The interaction between ROWS BETWEEN and ORDER BY can affect parallel query execution and indexing strategies.
3
Using ROWS BETWEEN with non-unique ORDER BY columns can produce subtle differences in results depending on physical row order.
When NOT to use
Avoid ROWS BETWEEN when you need value-based frames that include all rows with the same ORDER BY value; use RANGE BETWEEN instead. Also, for very large partitions with unbounded frames, consider pre-aggregating data or using summary tables to improve performance.
Production Patterns
Common patterns include running totals with ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW, moving averages with fixed preceding and following rows, and lag/lead calculations combined with frames for trend analysis. Production queries often combine frames with PARTITION BY to segment data by categories.
Connections
Sliding window algorithms
Both define a moving subset of data to compute results incrementally.
Understanding sliding windows in algorithms helps grasp how window frames move over rows to compute aggregates efficiently.
Time series analysis
Window frames enable calculations like moving averages and cumulative sums common in time series data.
Knowing window frames deepens understanding of how time-based trends and smoothing are computed in databases.
Signal processing
Windowing in signal processing and ROWS BETWEEN both select a subset of data points to analyze locally.
Recognizing this connection shows how local context matters in both data signals and database rows for meaningful calculations.
Common Pitfalls
#1Using ROWS BETWEEN without specifying frame boundaries defaults to an unexpected frame.
Wrong approach:SELECT SUM(sales) OVER (ORDER BY date ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING) FROM sales_data;
Correct approach:SELECT SUM(sales) OVER (ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) FROM sales_data;
Root cause:Misunderstanding default frame behavior leads to wrong cumulative calculations.
#2Confusing ROWS and RANGE frame types causes incorrect inclusion of rows.
Wrong approach:SELECT SUM(sales) OVER (ORDER BY date RANGE BETWEEN 1 PRECEDING AND CURRENT ROW) FROM sales_data;
Correct approach:SELECT SUM(sales) OVER (ORDER BY date ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) FROM sales_data;
Root cause:Not knowing that RANGE includes all rows with the same ORDER BY value, while ROWS counts physical rows.
#3Specifying frame boundaries that exclude the current row unintentionally.
Wrong approach:SELECT AVG(score) OVER (ORDER BY id ROWS BETWEEN 2 PRECEDING AND 1 PRECEDING) FROM test_scores;
Correct approach:SELECT AVG(score) OVER (ORDER BY id ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) FROM test_scores;
Root cause:Assuming current row is always included without checking frame boundaries.
Key Takeaways
ROWS BETWEEN lets you define a precise range of rows around the current row for window function calculations.
It counts physical rows relative to the current row, unlike RANGE which uses value ranges.
Frame boundaries adjust automatically at partition edges to avoid errors.
Choosing the right frame size balances calculation accuracy and query performance.
Understanding ROWS BETWEEN unlocks powerful analytics like running totals and moving averages in SQL.