SQL Practice Platform
Article

Understanding Window Frame Clauses in SQL – ROWS vs RANGE (With Simple Examples)

Understanding Window Frame Clauses in SQL – ROWS vs RANGE (With Simple Examples)

Hey, I’m Gaurav.

When I first learned window functions, I was comfortable with `PARTITION BY` and `ORDER BY`.  

But then I saw this:

```sql
SUM(salary) OVER (PARTITION BY department ORDER BY salary 
                  ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
```

And I got completely lost.

What is `ROWS BETWEEN`?  
What does `UNBOUNDED PRECEDING` mean?  
Why do we need a "frame"?

Today, I’ll explain Window Frame Clauses from the very beginning — exactly how I finally understood them.

We’ll use simple examples you can practice live on [sqlpractice.in](https://sqlpractice.in).

---

What is a Window Frame?

A window frame defines which rows should be included in the calculation for the current row.

Think of it like this:

> “For the current row, which previous or following rows should I consider when calculating SUM, AVG, MIN, MAX, etc.?”

By default, when you write `ORDER BY` in a window function, SQL applies a default frame. But most of the time, we need to define it explicitly for correct results.

There are two main ways to define the frame:

1. `ROWS` → Physical rows (count-based)
2. `RANGE` → Logical range (value-based)

---

1. ROWS BETWEEN (Most Commonly Used)

`ROWS` treats rows as physical positions.

Most Important Frame Types:

a) Running / Cumulative Total (Most Common)

```sql
SUM(amount) OVER (
    PARTITION BY customer_id 
    ORDER BY order_date
    ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
)
```

Meaning:  
Include all rows from the beginning of the partition up to the current row.

This is the standard way to calculate running total.

Practice Question:  
Show each order with its amount and the running total per customer.  
[Try it live →](https://sqlpractice.in/?question=running-total)

b) Moving Average / Rolling Window

```sql
AVG(amount) OVER (
    PARTITION BY customer_id 
    ORDER BY order_date
    ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
)
```

Meaning:  
Take the current row + previous 2 rows = 3-row moving average.

Practice Question:  
Calculate 3-order moving average of amount per customer.  
[Try it live →](https://sqlpractice.in/?question=moving-average)

c) Only Current Row

```sql
SUM(amount) OVER (
    PARTITION BY customer_id 
    ORDER BY order_date
    ROWS BETWEEN CURRENT ROW AND CURRENT ROW
)
```

d) Future Rows (Rare)

```sql
LEAD(amount, 1) OVER (...)   -- or
SUM(amount) OVER (... ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING)
```

---

2. RANGE BETWEEN (Logical Range)

`RANGE` works on values, not physical row count.

It is useful when you want to include rows with the same value.

Example:
```sql
SUM(salary) OVER (
    PARTITION BY department 
    ORDER BY salary
    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
)
```

Difference between ROWS and RANGE:

| Clause          | Based On       | Handles Ties          | Use Case                     |
|-----------------|----------------|-----------------------|------------------------------|
| `ROWS`          | Physical rows  | Treats ties separately| Running totals, moving avg   |
| `RANGE`         | Actual values  | Groups same values    | When values are same         |

Note: `RANGE` is less commonly used and not supported by all databases with complex frames.

---

How to Think About Window Frames (My Mental Model)

Whenever you write a window function with `ORDER BY`, ask yourself:

1. Do I want a running calculation?  
   → Use `ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW`

2. Do I want a moving window of last N rows?  
   → Use `ROWS BETWEEN N PRECEDING AND CURRENT ROW`

3. Do I want to include only the current row?  
   → `ROWS BETWEEN CURRENT ROW AND CURRENT ROW`

4. Do I want to look into the future?  
   → `ROWS BETWEEN CURRENT ROW AND N FOLLOWING`

Golden Rule:  
If you're calculating cumulative / running values → always explicitly write the frame.  
Default behavior can be confusing and database-dependent.

---

Common Interview Questions on Window Frame

1. What is the difference between `ROWS` and `RANGE`?
2. Write a query to calculate running total.
3. What is the default frame when you only write `ORDER BY`?
4. How would you calculate a 7-day moving average?

Practice Questions (Recommended)

- Running Total per customer  
- 3-order moving average  
- Compare current order with average of last 5 orders  
- Cumulative count of orders per customer

You can find all these in the Window Functions Pack on sqlpractice.in.

---

Final Thoughts

Window Frame Clauses were the missing piece for me.  
Once I understood that the frame defines "which rows participate in the calculation for the current row", everything clicked.

Start with `ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW` for running totals — it’s the most useful one.

The more you practice, the more natural it becomes to decide the right frame.

Go try these examples on [sqlpractice.in](https://sqlpractice.in) — especially the running total and moving average ones.

You’ll start seeing window functions as a powerful tool rather than a scary topic.



Keep practicing — one concept at a time! 💪

Building sqlpractice.in to help everyone master SQL for interviews — completely free.