SQL Window Functions: OVER Clause, PARTITION BY, ORDER BY, and Frames

Core window function syntax, partitions, ordering, and frame clauses for analytic SQL queries.

View
StandardDetailedCompact
Export
Copy the compact sheet, download it, or print it.
Download
`D` dense toggle · `C` copy all

OVER clause fundamentals

Start with the smallest patterns that make window functions click.

Count all rows without collapsing them

Return total row count on every row.

sqlANYcountover
sql
SELECT order_id,
       customer_id,
       COUNT(*) OVER () AS total_rows
FROM orders;

A window aggregate keeps detail rows intact while computing a value across the full result set.

Aggregate within a partition

Compute a per-customer total on every row.

sqlANYsumpartition
sql
SELECT order_id,
       customer_id,
       amount,
       SUM(amount) OVER (PARTITION BY customer_id) AS customer_total
FROM orders;

`PARTITION BY` resets the calculation for each logical group.

Assign row numbers inside each partition

Number rows in order within each customer.

sqlANYrow_numberorder by
sql
SELECT order_id,
       customer_id,
       created_at,
       ROW_NUMBER() OVER (
         PARTITION BY customer_id
         ORDER BY created_at DESC
       ) AS rn
FROM orders;

`ORDER BY` inside the window defines sequence for ranking and frame-aware calculations.

Reuse a named window

Avoid repeating a long window definition.

sqlANYwindowreuse
sql
SELECT order_id,
       amount,
       SUM(amount) OVER w AS running_sum,
       AVG(amount) OVER w AS running_avg
FROM orders
WINDOW w AS (
  PARTITION BY customer_id
  ORDER BY created_at
  ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
);

Named windows improve readability when several expressions share the same partition, order, and frame.

Explicit ROWS frame

Define exactly which physical rows are included.

sqlANYrowsframe
sql
SELECT created_at,
       amount,
       SUM(amount) OVER (
         ORDER BY created_at
         ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
       ) AS running_total
FROM orders;

Use `ROWS` when you want frame boundaries to follow row positions rather than peer groups.

Use RANGE for peer-aware frames

Group rows that share the same ordering value.

sqlANYrangepeers
sql
SELECT score,
       COUNT(*) OVER (
         ORDER BY score
         RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
       ) AS cumulative_count
FROM exam_results;

`RANGE` can treat rows with equal sort values as peers, which often changes cumulative results compared with `ROWS`.

Exclude the current row from a frame

Compare a row against all earlier rows only.

sqlANYframehistorical
sql
SELECT created_at,
       amount,
       AVG(amount) OVER (
         ORDER BY created_at
         ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
       ) AS avg_before_current
FROM orders;

This pattern is useful when you need a historical benchmark without including the current row in the average.

Frame clause cheatsheet

Quick examples of common frame shapes.

Current row only

Single-row frame.

sqlANYframe
sql
ROWS BETWEEN CURRENT ROW AND CURRENT ROW

Useful in examples and to contrast with broader frames.

Last 7 rows

Rolling seven-row frame.

sqlANYmoving-window
sql
ROWS BETWEEN 6 PRECEDING AND CURRENT ROW

A classic moving window for row-based smoothing.

Current and next 3 rows

Forward-looking frame.

sqlANYfollowing
sql
ROWS BETWEEN CURRENT ROW AND 3 FOLLOWING

Handy for queueing, forecast windows, or lead-like summaries.

Whole partition

Every row in the current partition.

sqlANYpartition
sql
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING

For some functions, this makes intent explicit and avoids dialect-specific defaults.

Recommended next

No recommendations yet.