πŸ•·οΈ Crawler Inspector

URL Lookup

Direct Parameter Lookup

Raw Queries and Responses

1. Shard Calculation

Query:
Response:
Calculated Shard: 89 (from laksa014)

2. Crawled Status Check

Query:
Response:

3. Robots.txt Check

Query:
Response:

4. Spam/Ban Check

Query:
Response:

5. Seen Status Check

ℹ️ Skipped - page is already crawled

πŸ“„
INDEXABLE
βœ…
CRAWLED
6 days ago
πŸ€–
ROBOTS ALLOWED

Page Info Filters

FilterStatusConditionDetails
HTTP statusPASSdownload_http_code = 200HTTP 200
Age cutoffPASSdownload_stamp > now() - 6 MONTH0.2 months ago
History dropPASSisNull(history_drop_reason)No drop reason
Spam/banPASSfh_dont_index != 1 AND ml_spam_score = 0ml_spam_score=0
CanonicalPASSmeta_canonical IS NULL OR = '' OR = src_unparsedNot set

Page Details

PropertyValue
URLhttps://clickhouse.com/docs/sql-reference/window-functions
Last Crawled2026-04-11 03:09:16 (6 days ago)
First Indexed2025-02-21 00:09:27 (1 year ago)
HTTP Status Code200
Meta TitleWindow Functions | ClickHouse Docs
Meta DescriptionOverview page for window functions
Meta Canonicalnull
Boilerpipe Text
Window functions let you perform calculations across a set of rows that are related to the current row. Some of the calculations that you can do are similar to those that can be done with an aggregate function, but a window function doesn't cause rows to be grouped into a single output - the individual rows are still returned. Standard window functions ​ ClickHouse supports the standard grammar for defining windows and window functions. The table below indicates whether a feature is currently supported. Feature Supported? ad hoc window specification ( count(*) over (partition by id order by time desc) ) βœ… expressions involving window functions, e.g. (count(*) over ()) / 2) βœ… WINDOW clause ( select ... from table window w as (partition by id) ) βœ… ROWS frame βœ… RANGE frame βœ… (the default) INTERVAL syntax for DateTime RANGE OFFSET frame ❌ (specify the number of seconds instead ( RANGE works with any numeric type).) GROUPS frame ❌ Calculating aggregate functions over a frame ( sum(value) over (order by time) ) βœ… (All aggregate functions are supported) rank() , dense_rank() , row_number() βœ… Alias: denseRank() percent_rank() βœ… Efficiently computes the relative standing of a value within a partition in a dataset. This function effectively replaces the more verbose and computationally intensive manual SQL calculation expressed as ifNull((rank() OVER(PARTITION BY x ORDER BY y) - 1) / nullif(count(1) OVER(PARTITION BY x) - 1, 0), 0) Alias: percentRank() cume_dist() βœ… Computes the cumulative distribution of a value within a group of values. Returns the percentage of rows with values less than or equal to the current row's value. lag/lead(value, offset) βœ… You can also use one of the following workarounds: 1) any(value) over (.... rows between <offset> preceding and <offset> preceding) , or following for lead 2) lagInFrame/leadInFrame , which are analogous, but respect the window frame. To get behavior identical to lag/lead , use rows between unbounded preceding and unbounded following ntile(buckets) βœ… Specify window like, (partition by x order by y rows between unbounded preceding and unbounded following). ClickHouse-specific window functions ​ There is also the following ClickHouse specific window function: nonNegativeDerivative(metric_column, timestamp_column[, INTERVAL X UNITS]) ​ Finds non-negative derivative for given metric_column by timestamp_column . INTERVAL can be omitted, default is INTERVAL 1 SECOND . The computed value is the following for each row: 0 for 1st row, metric i βˆ’ metric i βˆ’ 1 timestamp i βˆ’ timestamp i βˆ’ 1 βˆ— interval {\text{metric}_i - \text{metric}_{i-1} \over \text{timestamp}_i - \text{timestamp}_{i-1}} * \text{interval} for i t h i_{th} row. Syntax ​ aggregate_function (column_name) OVER ([[PARTITION BY grouping_column] [ORDER BY sorting_column] [ROWS or RANGE expression_to_bound_rows_within_the_group]] | [window_name]) FROM table_name WINDOW window_name as ([ [PARTITION BY grouping_column] [ORDER BY sorting_column] [ROWS or RANGE expression_to_bound_rows_within_the_group] ]) PARTITION BY - defines how to break a resultset into groups. ORDER BY - defines how to order rows inside the group during calculation aggregate_function. ROWS or RANGE - defines bounds of a frame, aggregate_function is calculated within a frame. WINDOW - allows multiple expressions to use the same window definition. PARTITION β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” <-- UNBOUNDED PRECEDING (BEGINNING of the PARTITION) β”‚ β”‚ β”‚ β”‚ β”‚=================β”‚ <-- N PRECEDING <─┐ β”‚ N ROWS β”‚ β”‚ F β”‚ Before CURRENT β”‚ β”‚ R β”‚~~~~~~~~~~~~~~~~~β”‚ <-- CURRENT ROW β”‚ A β”‚ M ROWS β”‚ β”‚ M β”‚ After CURRENT β”‚ β”‚ E β”‚=================β”‚ <-- M FOLLOWING <β”€β”˜ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ <--- UNBOUNDED FOLLOWING (END of the PARTITION) Functions ​ These functions can be used only as a window function. row_number() - Number the current row within its partition starting from 1. first_value(x) - Return the first value evaluated within its ordered frame. last_value(x) - Return the last value evaluated within its ordered frame. nth_value(x, offset) - Return the first non-NULL value evaluated against the nth row (offset) in its ordered frame. rank() - Rank the current row within its partition with gaps. dense_rank() - Rank the current row within its partition without gaps. lagInFrame(x) - Return a value evaluated at the row that is at a specified physical offset row before the current row within the ordered frame. leadInFrame(x) - Return a value evaluated at the row that is offset rows after the current row within the ordered frame. Examples ​ Let's have a look at some examples of how window functions can be used. Numbering rows ​ CREATE TABLE salaries ( ` team ` String , ` player ` String , ` salary ` UInt32 , ` position ` String ) Engine = Memory ; INSERT INTO salaries FORMAT Values ( 'Port Elizabeth Barbarians' , 'Gary Chen' , 195000 , 'F' ) , ( 'New Coreystad Archdukes' , 'Charles Juarez' , 190000 , 'F' ) , ( 'Port Elizabeth Barbarians' , 'Michael Stanley' , 150000 , 'D' ) , ( 'New Coreystad Archdukes' , 'Scott Harrison' , 150000 , 'D' ) , ( 'Port Elizabeth Barbarians' , 'Robert George' , 195000 , 'M' ) ; SELECT player , salary , row_number ( ) OVER ( ORDER BY salary ASC ) AS row FROM salaries ; β”Œβ”€player──────────┬─salary─┬─row─┐ β”‚ Michael Stanley β”‚ 150000 β”‚ 1 β”‚ β”‚ Scott Harrison β”‚ 150000 β”‚ 2 β”‚ β”‚ Charles Juarez β”‚ 190000 β”‚ 3 β”‚ β”‚ Gary Chen β”‚ 195000 β”‚ 4 β”‚ β”‚ Robert George β”‚ 195000 β”‚ 5 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜ SELECT player , salary , row_number ( ) OVER ( ORDER BY salary ASC ) AS row , rank ( ) OVER ( ORDER BY salary ASC ) AS rank , dense_rank ( ) OVER ( ORDER BY salary ASC ) AS denseRank FROM salaries ; β”Œβ”€player──────────┬─salary─┬─row─┬─rank─┬─denseRank─┐ β”‚ Michael Stanley β”‚ 150000 β”‚ 1 β”‚ 1 β”‚ 1 β”‚ β”‚ Scott Harrison β”‚ 150000 β”‚ 2 β”‚ 1 β”‚ 1 β”‚ β”‚ Charles Juarez β”‚ 190000 β”‚ 3 β”‚ 3 β”‚ 2 β”‚ β”‚ Gary Chen β”‚ 195000 β”‚ 4 β”‚ 4 β”‚ 3 β”‚ β”‚ Robert George β”‚ 195000 β”‚ 5 β”‚ 4 β”‚ 3 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ Aggregation functions ​ Compare each player's salary to the average for their team. SELECT player , salary , team , avg ( salary ) OVER ( PARTITION BY team ) AS teamAvg , salary - teamAvg AS diff FROM salaries ; β”Œβ”€player──────────┬─salary─┬─team──────────────────────┬─teamAvg─┬───diff─┐ β”‚ Charles Juarez β”‚ 190000 β”‚ New Coreystad Archdukes β”‚ 170000 β”‚ 20000 β”‚ β”‚ Scott Harrison β”‚ 150000 β”‚ New Coreystad Archdukes β”‚ 170000 β”‚ -20000 β”‚ β”‚ Gary Chen β”‚ 195000 β”‚ Port Elizabeth Barbarians β”‚ 180000 β”‚ 15000 β”‚ β”‚ Michael Stanley β”‚ 150000 β”‚ Port Elizabeth Barbarians β”‚ 180000 β”‚ -30000 β”‚ β”‚ Robert George β”‚ 195000 β”‚ Port Elizabeth Barbarians β”‚ 180000 β”‚ 15000 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”˜ Compare each player's salary to the maximum for their team. SELECT player , salary , team , max ( salary ) OVER ( PARTITION BY team ) AS teamMax , salary - teamMax AS diff FROM salaries ; β”Œβ”€player──────────┬─salary─┬─team──────────────────────┬─teamMax─┬───diff─┐ β”‚ Charles Juarez β”‚ 190000 β”‚ New Coreystad Archdukes β”‚ 190000 β”‚ 0 β”‚ β”‚ Scott Harrison β”‚ 150000 β”‚ New Coreystad Archdukes β”‚ 190000 β”‚ -40000 β”‚ β”‚ Gary Chen β”‚ 195000 β”‚ Port Elizabeth Barbarians β”‚ 195000 β”‚ 0 β”‚ β”‚ Michael Stanley β”‚ 150000 β”‚ Port Elizabeth Barbarians β”‚ 195000 β”‚ -45000 β”‚ β”‚ Robert George β”‚ 195000 β”‚ Port Elizabeth Barbarians β”‚ 195000 β”‚ 0 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”˜ Partitioning by column ​ CREATE TABLE wf_partition ( ` part_key ` UInt64 , ` value ` UInt64 , ` order ` UInt64 ) ENGINE = Memory ; INSERT INTO wf_partition FORMAT Values ( 1 , 1 , 1 ) , ( 1 , 2 , 2 ) , ( 1 , 3 , 3 ) , ( 2 , 0 , 0 ) , ( 3 , 0 , 0 ) ; SELECT part_key , value , order , groupArray ( value ) OVER ( PARTITION BY part_key ) AS frame_values FROM wf_partition ORDER BY part_key ASC , value ASC ; β”Œβ”€part_key─┬─ value ─┬─ order ─┬─frame_values─┐ β”‚ 1 β”‚ 1 β”‚ 1 β”‚ [ 1 , 2 , 3 ] β”‚ < ┐ β”‚ 1 β”‚ 2 β”‚ 2 β”‚ [ 1 , 2 , 3 ] β”‚ β”‚ 1 - st group β”‚ 1 β”‚ 3 β”‚ 3 β”‚ [ 1 , 2 , 3 ] β”‚ < β”˜ β”‚ 2 β”‚ 0 β”‚ 0 β”‚ [ 0 ] β”‚ < - 2 - nd group β”‚ 3 β”‚ 0 β”‚ 0 β”‚ [ 0 ] β”‚ < - 3 - d group β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ Frame bounding ​ CREATE TABLE wf_frame ( ` part_key ` UInt64 , ` value ` UInt64 , ` order ` UInt64 ) ENGINE = Memory ; INSERT INTO wf_frame FORMAT Values ( 1 , 1 , 1 ) , ( 1 , 2 , 2 ) , ( 1 , 3 , 3 ) , ( 1 , 4 , 4 ) , ( 1 , 5 , 5 ) ; -- Frame is bounded by bounds of a partition (BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) SELECT part_key , value , order , groupArray ( value ) OVER ( PARTITION BY part_key ORDER BY order ASC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) AS frame_values FROM wf_frame ORDER BY part_key ASC , value ASC ; β”Œβ”€part_key─┬─ value ─┬─ order ─┬─frame_values─┐ β”‚ 1 β”‚ 1 β”‚ 1 β”‚ [ 1 , 2 , 3 , 4 , 5 ] β”‚ β”‚ 1 β”‚ 2 β”‚ 2 β”‚ [ 1 , 2 , 3 , 4 , 5 ] β”‚ β”‚ 1 β”‚ 3 β”‚ 3 β”‚ [ 1 , 2 , 3 , 4 , 5 ] β”‚ β”‚ 1 β”‚ 4 β”‚ 4 β”‚ [ 1 , 2 , 3 , 4 , 5 ] β”‚ β”‚ 1 β”‚ 5 β”‚ 5 β”‚ [ 1 , 2 , 3 , 4 , 5 ] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -- short form - no bound expression, no order by, -- an equalent of `ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING` SELECT part_key , value , order , groupArray ( value ) OVER ( PARTITION BY part_key ) AS frame_values_short , groupArray ( value ) OVER ( PARTITION BY part_key ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) AS frame_values FROM wf_frame ORDER BY part_key ASC , value ASC ; β”Œβ”€part_key─┬─ value ─┬─ order ─┬─frame_values_short─┬─frame_values─┐ β”‚ 1 β”‚ 1 β”‚ 1 β”‚ [ 1 , 2 , 3 , 4 , 5 ] β”‚ [ 1 , 2 , 3 , 4 , 5 ] β”‚ β”‚ 1 β”‚ 2 β”‚ 2 β”‚ [ 1 , 2 , 3 , 4 , 5 ] β”‚ [ 1 , 2 , 3 , 4 , 5 ] β”‚ β”‚ 1 β”‚ 3 β”‚ 3 β”‚ [ 1 , 2 , 3 , 4 , 5 ] β”‚ [ 1 , 2 , 3 , 4 , 5 ] β”‚ β”‚ 1 β”‚ 4 β”‚ 4 β”‚ [ 1 , 2 , 3 , 4 , 5 ] β”‚ [ 1 , 2 , 3 , 4 , 5 ] β”‚ β”‚ 1 β”‚ 5 β”‚ 5 β”‚ [ 1 , 2 , 3 , 4 , 5 ] β”‚ [ 1 , 2 , 3 , 4 , 5 ] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -- frame is bounded by the beginning of a partition and the current row SELECT part_key , value , order , groupArray ( value ) OVER ( PARTITION BY part_key ORDER BY order ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS frame_values FROM wf_frame ORDER BY part_key ASC , value ASC ; β”Œβ”€part_key─┬─ value ─┬─ order ─┬─frame_values─┐ β”‚ 1 β”‚ 1 β”‚ 1 β”‚ [ 1 ] β”‚ β”‚ 1 β”‚ 2 β”‚ 2 β”‚ [ 1 , 2 ] β”‚ β”‚ 1 β”‚ 3 β”‚ 3 β”‚ [ 1 , 2 , 3 ] β”‚ β”‚ 1 β”‚ 4 β”‚ 4 β”‚ [ 1 , 2 , 3 , 4 ] β”‚ β”‚ 1 β”‚ 5 β”‚ 5 β”‚ [ 1 , 2 , 3 , 4 , 5 ] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -- short form (frame is bounded by the beginning of a partition and the current row) -- an equalent of `ORDER BY order ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW` SELECT part_key , value , order , groupArray ( value ) OVER ( PARTITION BY part_key ORDER BY order ASC ) AS frame_values_short , groupArray ( value ) OVER ( PARTITION BY part_key ORDER BY order ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS frame_values FROM wf_frame ORDER BY part_key ASC , value ASC ; β”Œβ”€part_key─┬─ value ─┬─ order ─┬─frame_values_short─┬─frame_values─┐ β”‚ 1 β”‚ 1 β”‚ 1 β”‚ [ 1 ] β”‚ [ 1 ] β”‚ β”‚ 1 β”‚ 2 β”‚ 2 β”‚ [ 1 , 2 ] β”‚ [ 1 , 2 ] β”‚ β”‚ 1 β”‚ 3 β”‚ 3 β”‚ [ 1 , 2 , 3 ] β”‚ [ 1 , 2 , 3 ] β”‚ β”‚ 1 β”‚ 4 β”‚ 4 β”‚ [ 1 , 2 , 3 , 4 ] β”‚ [ 1 , 2 , 3 , 4 ] β”‚ β”‚ 1 β”‚ 5 β”‚ 5 β”‚ [ 1 , 2 , 3 , 4 , 5 ] β”‚ [ 1 , 2 , 3 , 4 , 5 ] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -- frame is bounded by the beginning of a partition and the current row, but order is backward SELECT part_key , value , order , groupArray ( value ) OVER ( PARTITION BY part_key ORDER BY order DESC ) AS frame_values FROM wf_frame ORDER BY part_key ASC , value ASC ; β”Œβ”€part_key─┬─ value ─┬─ order ─┬─frame_values─┐ β”‚ 1 β”‚ 1 β”‚ 1 β”‚ [ 5 , 4 , 3 , 2 , 1 ] β”‚ β”‚ 1 β”‚ 2 β”‚ 2 β”‚ [ 5 , 4 , 3 , 2 ] β”‚ β”‚ 1 β”‚ 3 β”‚ 3 β”‚ [ 5 , 4 , 3 ] β”‚ β”‚ 1 β”‚ 4 β”‚ 4 β”‚ [ 5 , 4 ] β”‚ β”‚ 1 β”‚ 5 β”‚ 5 β”‚ [ 5 ] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -- sliding frame - 1 PRECEDING ROW AND CURRENT ROW SELECT part_key , value , order , groupArray ( value ) OVER ( PARTITION BY part_key ORDER BY order ASC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW ) AS frame_values FROM wf_frame ORDER BY part_key ASC , value ASC ; β”Œβ”€part_key─┬─ value ─┬─ order ─┬─frame_values─┐ β”‚ 1 β”‚ 1 β”‚ 1 β”‚ [ 1 ] β”‚ β”‚ 1 β”‚ 2 β”‚ 2 β”‚ [ 1 , 2 ] β”‚ β”‚ 1 β”‚ 3 β”‚ 3 β”‚ [ 2 , 3 ] β”‚ β”‚ 1 β”‚ 4 β”‚ 4 β”‚ [ 3 , 4 ] β”‚ β”‚ 1 β”‚ 5 β”‚ 5 β”‚ [ 4 , 5 ] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -- sliding frame - ROWS BETWEEN 1 PRECEDING AND UNBOUNDED FOLLOWING SELECT part_key , value , order , groupArray ( value ) OVER ( PARTITION BY part_key ORDER BY order ASC ROWS BETWEEN 1 PRECEDING AND UNBOUNDED FOLLOWING ) AS frame_values FROM wf_frame ORDER BY part_key ASC , value ASC ; β”Œβ”€part_key─┬─ value ─┬─ order ─┬─frame_values─┐ β”‚ 1 β”‚ 1 β”‚ 1 β”‚ [ 1 , 2 , 3 , 4 , 5 ] β”‚ β”‚ 1 β”‚ 2 β”‚ 2 β”‚ [ 1 , 2 , 3 , 4 , 5 ] β”‚ β”‚ 1 β”‚ 3 β”‚ 3 β”‚ [ 2 , 3 , 4 , 5 ] β”‚ β”‚ 1 β”‚ 4 β”‚ 4 β”‚ [ 3 , 4 , 5 ] β”‚ β”‚ 1 β”‚ 5 β”‚ 5 β”‚ [ 4 , 5 ] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -- row_number does not respect the frame, so rn_1 = rn_2 = rn_3 != rn_4 SELECT part_key , value , order , groupArray ( value ) OVER w1 AS frame_values , row_number ( ) OVER w1 AS rn_1 , sum ( 1 ) OVER w1 AS rn_2 , row_number ( ) OVER w2 AS rn_3 , sum ( 1 ) OVER w2 AS rn_4 FROM wf_frame WINDOW w1 AS ( PARTITION BY part_key ORDER BY order DESC ) , w2 AS ( PARTITION BY part_key ORDER BY order DESC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW ) ORDER BY part_key ASC , value ASC ; β”Œβ”€part_key─┬─ value ─┬─ order ─┬─frame_values─┬─rn_1─┬─rn_2─┬─rn_3─┬─rn_4─┐ β”‚ 1 β”‚ 1 β”‚ 1 β”‚ [ 5 , 4 , 3 , 2 , 1 ] β”‚ 5 β”‚ 5 β”‚ 5 β”‚ 2 β”‚ β”‚ 1 β”‚ 2 β”‚ 2 β”‚ [ 5 , 4 , 3 , 2 ] β”‚ 4 β”‚ 4 β”‚ 4 β”‚ 2 β”‚ β”‚ 1 β”‚ 3 β”‚ 3 β”‚ [ 5 , 4 , 3 ] β”‚ 3 β”‚ 3 β”‚ 3 β”‚ 2 β”‚ β”‚ 1 β”‚ 4 β”‚ 4 β”‚ [ 5 , 4 ] β”‚ 2 β”‚ 2 β”‚ 2 β”‚ 2 β”‚ β”‚ 1 β”‚ 5 β”‚ 5 β”‚ [ 5 ] β”‚ 1 β”‚ 1 β”‚ 1 β”‚ 1 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”˜ -- first_value and last_value respect the frame SELECT groupArray ( value ) OVER w1 AS frame_values_1 , first_value ( value ) OVER w1 AS first_value_1 , last_value ( value ) OVER w1 AS last_value_1 , groupArray ( value ) OVER w2 AS frame_values_2 , first_value ( value ) OVER w2 AS first_value_2 , last_value ( value ) OVER w2 AS last_value_2 FROM wf_frame WINDOW w1 AS ( PARTITION BY part_key ORDER BY order ASC ) , w2 AS ( PARTITION BY part_key ORDER BY order ASC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW ) ORDER BY part_key ASC , value ASC ; β”Œβ”€frame_values_1─┬─first_value_1─┬─last_value_1─┬─frame_values_2─┬─first_value_2─┬─last_value_2─┐ β”‚ [ 1 ] β”‚ 1 β”‚ 1 β”‚ [ 1 ] β”‚ 1 β”‚ 1 β”‚ β”‚ [ 1 , 2 ] β”‚ 1 β”‚ 2 β”‚ [ 1 , 2 ] β”‚ 1 β”‚ 2 β”‚ β”‚ [ 1 , 2 , 3 ] β”‚ 1 β”‚ 3 β”‚ [ 2 , 3 ] β”‚ 2 β”‚ 3 β”‚ β”‚ [ 1 , 2 , 3 , 4 ] β”‚ 1 β”‚ 4 β”‚ [ 3 , 4 ] β”‚ 3 β”‚ 4 β”‚ β”‚ [ 1 , 2 , 3 , 4 , 5 ] β”‚ 1 β”‚ 5 β”‚ [ 4 , 5 ] β”‚ 4 β”‚ 5 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -- second value within the frame SELECT groupArray ( value ) OVER w1 AS frame_values_1 , nth_value ( value , 2 ) OVER w1 AS second_value FROM wf_frame WINDOW w1 AS ( PARTITION BY part_key ORDER BY order ASC ROWS BETWEEN 3 PRECEDING AND CURRENT ROW ) ORDER BY part_key ASC , value ASC ; β”Œβ”€frame_values_1─┬─second_value─┐ β”‚ [ 1 ] β”‚ 0 β”‚ β”‚ [ 1 , 2 ] β”‚ 2 β”‚ β”‚ [ 1 , 2 , 3 ] β”‚ 2 β”‚ β”‚ [ 1 , 2 , 3 , 4 ] β”‚ 2 β”‚ β”‚ [ 2 , 3 , 4 , 5 ] β”‚ 3 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -- second value within the frame + Null for missing values SELECT groupArray ( value ) OVER w1 AS frame_values_1 , nth_value ( toNullable ( value ) , 2 ) OVER w1 AS second_value FROM wf_frame WINDOW w1 AS ( PARTITION BY part_key ORDER BY order ASC ROWS BETWEEN 3 PRECEDING AND CURRENT ROW ) ORDER BY part_key ASC , value ASC ; β”Œβ”€frame_values_1─┬─second_value─┐ β”‚ [ 1 ] β”‚ ᴺᡁᴸᴸ β”‚ β”‚ [ 1 , 2 ] β”‚ 2 β”‚ β”‚ [ 1 , 2 , 3 ] β”‚ 2 β”‚ β”‚ [ 1 , 2 , 3 , 4 ] β”‚ 2 β”‚ β”‚ [ 2 , 3 , 4 , 5 ] β”‚ 3 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ Real world examples ​ The following examples solve common real-world problems. Maximum/total salary per department ​ CREATE TABLE employees ( ` department ` String , ` employee_name ` String , ` salary ` Float ) ENGINE = Memory ; INSERT INTO employees FORMAT Values ( 'Finance' , 'Jonh' , 200 ) , ( 'Finance' , 'Joan' , 210 ) , ( 'Finance' , 'Jean' , 505 ) , ( 'IT' , 'Tim' , 200 ) , ( 'IT' , 'Anna' , 300 ) , ( 'IT' , 'Elen' , 500 ) ; SELECT department , employee_name AS emp , salary , max_salary_per_dep , total_salary_per_dep , round ( ( salary / total_salary_per_dep ) * 100 , 2 ) AS ` share_per_dep(%) ` FROM ( SELECT department , employee_name , salary , max ( salary ) OVER wndw AS max_salary_per_dep , sum ( salary ) OVER wndw AS total_salary_per_dep FROM employees WINDOW wndw AS ( PARTITION BY department ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) ORDER BY department ASC , employee_name ASC ) ; β”Œβ”€department─┬─emp──┬─salary─┬─max_salary_per_dep─┬─total_salary_per_dep─┬─share_per_dep ( % ) ─┐ β”‚ Finance β”‚ Jean β”‚ 505 β”‚ 505 β”‚ 915 β”‚ 55.19 β”‚ β”‚ Finance β”‚ Joan β”‚ 210 β”‚ 505 β”‚ 915 β”‚ 22.95 β”‚ β”‚ Finance β”‚ Jonh β”‚ 200 β”‚ 505 β”‚ 915 β”‚ 21.86 β”‚ β”‚ IT β”‚ Anna β”‚ 300 β”‚ 500 β”‚ 1000 β”‚ 30 β”‚ β”‚ IT β”‚ Elen β”‚ 500 β”‚ 500 β”‚ 1000 β”‚ 50 β”‚ β”‚ IT β”‚ Tim β”‚ 200 β”‚ 500 β”‚ 1000 β”‚ 20 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ Cumulative sum ​ CREATE TABLE warehouse ( ` item ` String , ` ts ` DateTime , ` value ` Float ) ENGINE = Memory INSERT INTO warehouse VALUES ( 'sku38' , '2020-01-01' , 9 ) , ( 'sku38' , '2020-02-01' , 1 ) , ( 'sku38' , '2020-03-01' , - 4 ) , ( 'sku1' , '2020-01-01' , 1 ) , ( 'sku1' , '2020-02-01' , 1 ) , ( 'sku1' , '2020-03-01' , 1 ) ; SELECT item, ts, value, sum(value) OVER (PARTITION BY item ORDER BY ts ASC) AS stock_balance FROM warehouse ORDER BY item ASC, ts ASC; β”Œβ”€item──┬──────────────────ts─┬─value─┬─stock_balance─┐ β”‚ sku1 β”‚ 2020-01-01 00:00:00 β”‚ 1 β”‚ 1 β”‚ β”‚ sku1 β”‚ 2020-02-01 00:00:00 β”‚ 1 β”‚ 2 β”‚ β”‚ sku1 β”‚ 2020-03-01 00:00:00 β”‚ 1 β”‚ 3 β”‚ β”‚ sku38 β”‚ 2020-01-01 00:00:00 β”‚ 9 β”‚ 9 β”‚ β”‚ sku38 β”‚ 2020-02-01 00:00:00 β”‚ 1 β”‚ 10 β”‚ β”‚ sku38 β”‚ 2020-03-01 00:00:00 β”‚ -4 β”‚ 6 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ Moving / sliding average (per 3 rows) ​ CREATE TABLE sensors ( `metric` String, `ts` DateTime, `value` Float ) ENGINE = Memory; insert into sensors values('cpu_temp', '2020-01-01 00:00:00', 87), ('cpu_temp', '2020-01-01 00:00:01', 77), ('cpu_temp', '2020-01-01 00:00:02', 93), ('cpu_temp', '2020-01-01 00:00:03', 87), ('cpu_temp', '2020-01-01 00:00:04', 87), ('cpu_temp', '2020-01-01 00:00:05', 87), ('cpu_temp', '2020-01-01 00:00:06', 87), ('cpu_temp', '2020-01-01 00:00:07', 87); SELECT metric, ts, value, avg(value) OVER ( PARTITION BY metric ORDER BY ts ASC ROWS BETWEEN 2 PRECEDING AND CURRENT ROW ) AS moving_avg_temp FROM sensors ORDER BY metric ASC, ts ASC; β”Œβ”€metric───┬──────────────────ts─┬─value─┬───moving_avg_temp─┐ β”‚ cpu_temp β”‚ 2020-01-01 00:00:00 β”‚ 87 β”‚ 87 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:00:01 β”‚ 77 β”‚ 82 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:00:02 β”‚ 93 β”‚ 85.66666666666667 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:00:03 β”‚ 87 β”‚ 85.66666666666667 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:00:04 β”‚ 87 β”‚ 89 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:00:05 β”‚ 87 β”‚ 87 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:00:06 β”‚ 87 β”‚ 87 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:00:07 β”‚ 87 β”‚ 87 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ Moving / sliding average (per 10 seconds) ​ SELECT metric, ts, value, avg(value) OVER (PARTITION BY metric ORDER BY ts RANGE BETWEEN 10 PRECEDING AND CURRENT ROW) AS moving_avg_10_seconds_temp FROM sensors ORDER BY metric ASC, ts ASC; β”Œβ”€metric───┬──────────────────ts─┬─value─┬─moving_avg_10_seconds_temp─┐ β”‚ cpu_temp β”‚ 2020-01-01 00:00:00 β”‚ 87 β”‚ 87 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:01:10 β”‚ 77 β”‚ 77 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:02:20 β”‚ 93 β”‚ 93 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:03:30 β”‚ 87 β”‚ 87 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:04:40 β”‚ 87 β”‚ 87 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:05:50 β”‚ 87 β”‚ 87 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:06:00 β”‚ 87 β”‚ 87 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:07:10 β”‚ 87 β”‚ 87 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ Moving / sliding average (per 10 days) ​ Temperature is stored with second precision, but using Range and ORDER BY toDate(ts) we form a frame with the size of 10 units, and because of toDate(ts) the unit is a day. CREATE TABLE sensors ( `metric` String, `ts` DateTime, `value` Float ) ENGINE = Memory; insert into sensors values('ambient_temp', '2020-01-01 00:00:00', 16), ('ambient_temp', '2020-01-01 12:00:00', 16), ('ambient_temp', '2020-01-02 11:00:00', 9), ('ambient_temp', '2020-01-02 12:00:00', 9), ('ambient_temp', '2020-02-01 10:00:00', 10), ('ambient_temp', '2020-02-01 12:00:00', 10), ('ambient_temp', '2020-02-10 12:00:00', 12), ('ambient_temp', '2020-02-10 13:00:00', 12), ('ambient_temp', '2020-02-20 12:00:01', 16), ('ambient_temp', '2020-03-01 12:00:00', 16), ('ambient_temp', '2020-03-01 12:00:00', 16), ('ambient_temp', '2020-03-01 12:00:00', 16); SELECT metric, ts, value, round(avg(value) OVER (PARTITION BY metric ORDER BY toDate(ts) RANGE BETWEEN 10 PRECEDING AND CURRENT ROW),2) AS moving_avg_10_days_temp FROM sensors ORDER BY metric ASC, ts ASC; β”Œβ”€metric───────┬──────────────────ts─┬─value─┬─moving_avg_10_days_temp─┐ β”‚ ambient_temp β”‚ 2020-01-01 00:00:00 β”‚ 16 β”‚ 16 β”‚ β”‚ ambient_temp β”‚ 2020-01-01 12:00:00 β”‚ 16 β”‚ 16 β”‚ β”‚ ambient_temp β”‚ 2020-01-02 11:00:00 β”‚ 9 β”‚ 12.5 β”‚ β”‚ ambient_temp β”‚ 2020-01-02 12:00:00 β”‚ 9 β”‚ 12.5 β”‚ β”‚ ambient_temp β”‚ 2020-02-01 10:00:00 β”‚ 10 β”‚ 10 β”‚ β”‚ ambient_temp β”‚ 2020-02-01 12:00:00 β”‚ 10 β”‚ 10 β”‚ β”‚ ambient_temp β”‚ 2020-02-10 12:00:00 β”‚ 12 β”‚ 11 β”‚ β”‚ ambient_temp β”‚ 2020-02-10 13:00:00 β”‚ 12 β”‚ 11 β”‚ β”‚ ambient_temp β”‚ 2020-02-20 12:00:01 β”‚ 16 β”‚ 13.33 β”‚ β”‚ ambient_temp β”‚ 2020-03-01 12:00:00 β”‚ 16 β”‚ 16 β”‚ β”‚ ambient_temp β”‚ 2020-03-01 12:00:00 β”‚ 16 β”‚ 16 β”‚ β”‚ ambient_temp β”‚ 2020-03-01 12:00:00 β”‚ 16 β”‚ 16 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ References ​ GitHub Issues ​ The roadmap for the initial support of window functions is in this issue . All GitHub issues related to window functions have the comp-window-functions tag. Tests ​ These tests contain the examples of the currently supported grammar: https://github.com/ClickHouse/ClickHouse/blob/master/tests/performance/window_functions.xml https://github.com/ClickHouse/ClickHouse/blob/master/tests/queries/0_stateless/01591_window_functions.sql Postgres Docs ​ https://www.postgresql.org/docs/current/sql-select.html#SQL-WINDOW https://www.postgresql.org/docs/devel/sql-expressions.html#SYNTAX-WINDOW-FUNCTIONS https://www.postgresql.org/docs/devel/functions-window.html https://www.postgresql.org/docs/devel/tutorial-window.html MySQL Docs ​ https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html https://dev.mysql.com/doc/refman/8.0/en/window-functions-usage.html https://dev.mysql.com/doc/refman/8.0/en/window-functions-frames.html Related Content ​ Blog: Working with time series data in ClickHouse Blog: Window and array functions for Git commit sequences Blog: Getting Data Into ClickHouse - Part 3 - Using S3
Markdown
[Skip to main content](https://clickhouse.com/docs/sql-reference/window-functions#__docusaurus_skipToContent_fallback) [![ClickHouse](https://clickhouse.com/docs/img/ch_logo_docs.svg)](https://clickhouse.com/) - [Products](https://clickhouse.com/docs/sql-reference/window-functions) - [ClickHouse Cloud Best way to use ClickHouse. Available on AWS, GCP, and Azure.](https://clickhouse.com/cloud) - [BYOC (Bring Your Own Cloud) The fully managed ClickHouse Cloud service, Can be deployed in your AWS account.](https://clickhouse.com/cloud/bring-your-own-cloud) - [ClickHouse Set up a database with open-source ClickHouse. ClickHouse](https://clickhouse.com/clickhouse) - [Discover more than 100 integrations.](https://clickhouse.com/integrations) [Discover more than 100 integrations.](https://clickhouse.com/integrations) - [Use cases](https://clickhouse.com/docs/sql-reference/window-functions) - [Real-time analytics](https://clickhouse.com/use-cases/real-time-analytics) - [Machine Learning & Generative AI](https://clickhouse.com/use-cases/machine-learning-and-data-science) - [Business Intelligence](https://clickhouse.com/use-cases/data-warehousing) - [Logs, Events, Traces](https://clickhouse.com/use-cases/observability) - [All use cases](https://clickhouse.com/use-cases) [All use cases](https://clickhouse.com/use-cases) - [Documentation](https://clickhouse.com/docs) - [Resources](https://clickhouse.com/docs/sql-reference/window-functions) - [User stories](https://clickhouse.com/user-stories) - [Blog](https://clickhouse.com/blog) - [Events](https://clickhouse.com/company/events) - [Learning and certification](https://clickhouse.com/learn) - [Comparison](https://clickhouse.com/docs/sql-reference/window-functions) - [BigQuery](https://clickhouse.com/comparison/bigquery) - [PostgreSQL](https://clickhouse.com/comparison/postgresql) - [Redshift](https://clickhouse.com/comparison/redshift) - [Rockset](https://clickhouse.com/comparison/rockset) - [Snowflake](https://clickhouse.com/comparison/snowflake) - [Video](https://clickhouse.com/videos) - [Demo](https://clickhouse.com/demos) - [Pricing](https://clickhouse.com/pricing) - [Contact](https://clickhouse.com/company/contact?loc=nav) [46\.8k](https://github.com/ClickHouse/ClickHouse?utm_source=clickhouse&utm_medium=website&utm_campaign=website-nav) [Search`Ctrl``K`](https://clickhouse.com/docs/search) [Sign in](https://console.clickhouse.cloud/signIn?loc=docs-nav-signIn-cta&glxid=ec987698-9313-4186-9781-be5fd1b64e13&pagePath=%2Fdocs%2Fsql-reference%2Fwindow-functions&origPath=%2Fdocs%2Fsql-reference%2Fwindow-functions&utm_ga=GA1.1.1971283203.1775876958) [Get started](https://console.clickhouse.cloud/signUp?loc=docs-nav-signUp-cta&glxid=ec987698-9313-4186-9781-be5fd1b64e13&pagePath=%2Fdocs%2Fsql-reference%2Fwindow-functions&origPath=%2Fdocs%2Fsql-reference%2Fwindow-functions&utm_ga=GA1.1.1971283203.1775876958) [Get started](https://clickhouse.com/docs/introduction-clickhouse) [Cloud](https://clickhouse.com/docs/cloud/overview) [Manage data](https://clickhouse.com/docs/updating-data) [Server admin](https://clickhouse.com/docs/guides/manage-and-deploy-index) [Reference](https://clickhouse.com/docs/sql-reference) [Integrations](https://clickhouse.com/docs/integrations) [ClickStack](https://clickhouse.com/docs/use-cases/observability/clickstack/overview) [chDB](https://clickhouse.com/docs/chdb) [About](https://clickhouse.com/docs/about) [Knowledge Base](https://clickhouse.com/docs/knowledgebase) [English](https://clickhouse.com/docs/sql-reference/window-functions) - [English](https://clickhouse.com/docs/sql-reference/window-functions) - [ζ—₯本θͺž](https://clickhouse.com/docs/jp/sql-reference/window-functions) - [δΈ­ζ–‡](https://clickhouse.com/docs/zh/sql-reference/window-functions) - [Русский](https://clickhouse.com/docs/ru/sql-reference/window-functions) - [ν•œκ΅­μ–΄](https://clickhouse.com/docs/ko/sql-reference/window-functions) [Skip to main content](https://clickhouse.com/docs/sql-reference/window-functions#__docusaurus_skipToContent_fallback) [![ClickHouse](https://clickhouse.com/docs/img/ch_logo_docs.svg)](https://clickhouse.com/) - [Products](https://clickhouse.com/docs/sql-reference/window-functions) - [ClickHouse Cloud Best way to use ClickHouse. Available on AWS, GCP, and Azure.](https://clickhouse.com/cloud) - [BYOC (Bring Your Own Cloud) The fully managed ClickHouse Cloud service, Can be deployed in your AWS account.](https://clickhouse.com/cloud/bring-your-own-cloud) - [ClickHouse Set up a database with open-source ClickHouse. ClickHouse](https://clickhouse.com/clickhouse) - [Discover more than 100 integrations.](https://clickhouse.com/integrations) [Discover more than 100 integrations.](https://clickhouse.com/integrations) - [Use cases](https://clickhouse.com/docs/sql-reference/window-functions) - [Real-time analytics](https://clickhouse.com/use-cases/real-time-analytics) - [Machine Learning & Generative AI](https://clickhouse.com/use-cases/machine-learning-and-data-science) - [Business Intelligence](https://clickhouse.com/use-cases/data-warehousing) - [Logs, Events, Traces](https://clickhouse.com/use-cases/observability) - [All use cases](https://clickhouse.com/use-cases) [All use cases](https://clickhouse.com/use-cases) - [Documentation](https://clickhouse.com/docs) - [Resources](https://clickhouse.com/docs/sql-reference/window-functions) - [User stories](https://clickhouse.com/user-stories) - [Blog](https://clickhouse.com/blog) - [Events](https://clickhouse.com/company/events) - [Learning and certification](https://clickhouse.com/learn) - [Comparison](https://clickhouse.com/docs/sql-reference/window-functions) - [BigQuery](https://clickhouse.com/comparison/bigquery) - [PostgreSQL](https://clickhouse.com/comparison/postgresql) - [Redshift](https://clickhouse.com/comparison/redshift) - [Rockset](https://clickhouse.com/comparison/rockset) - [Snowflake](https://clickhouse.com/comparison/snowflake) - [Video](https://clickhouse.com/videos) - [Demo](https://clickhouse.com/demos) - [Pricing](https://clickhouse.com/pricing) - [Contact](https://clickhouse.com/company/contact?loc=nav) [46\.8k](https://github.com/ClickHouse/ClickHouse?utm_source=clickhouse&utm_medium=website&utm_campaign=website-nav) [Search`Ctrl``K`](https://clickhouse.com/docs/search) [Sign in](https://console.clickhouse.cloud/signIn?loc=docs-nav-signIn-cta&glxid=ec987698-9313-4186-9781-be5fd1b64e13&pagePath=%2Fdocs%2Fsql-reference%2Fwindow-functions&origPath=%2Fdocs%2Fsql-reference%2Fwindow-functions&utm_ga=GA1.1.1971283203.1775876958) [Get started](https://console.clickhouse.cloud/signUp?loc=docs-nav-signUp-cta&glxid=ec987698-9313-4186-9781-be5fd1b64e13&pagePath=%2Fdocs%2Fsql-reference%2Fwindow-functions&origPath=%2Fdocs%2Fsql-reference%2Fwindow-functions&utm_ga=GA1.1.1971283203.1775876958) [Get started](https://clickhouse.com/docs/introduction-clickhouse) [Cloud](https://clickhouse.com/docs/cloud/overview) [Manage data](https://clickhouse.com/docs/updating-data) [Server admin](https://clickhouse.com/docs/guides/manage-and-deploy-index) [Reference](https://clickhouse.com/docs/sql-reference) [Integrations](https://clickhouse.com/docs/integrations) [ClickStack](https://clickhouse.com/docs/use-cases/observability/clickstack/overview) [chDB](https://clickhouse.com/docs/chdb) [About](https://clickhouse.com/docs/about) [Knowledge Base](https://clickhouse.com/docs/knowledgebase) [English](https://clickhouse.com/docs/sql-reference/window-functions) - [English](https://clickhouse.com/docs/sql-reference/window-functions) - [ζ—₯本θͺž](https://clickhouse.com/docs/jp/sql-reference/window-functions) - [δΈ­ζ–‡](https://clickhouse.com/docs/zh/sql-reference/window-functions) - [Русский](https://clickhouse.com/docs/ru/sql-reference/window-functions) - [ν•œκ΅­μ–΄](https://clickhouse.com/docs/ko/sql-reference/window-functions) [Search`Ctrl``K`](https://clickhouse.com/docs/search) - [Introduction](https://clickhouse.com/docs/sql-reference) - [Syntax](https://clickhouse.com/docs/sql-reference/syntax) - [Input and Output Formats](https://clickhouse.com/docs/sql-reference/formats) - [Data types](https://clickhouse.com/docs/sql-reference/data-types) - [Statements](https://clickhouse.com/docs/sql-reference/statements) - [Operators](https://clickhouse.com/docs/sql-reference/operators) - [Engines](https://clickhouse.com/docs/engines) - [Database Engines](https://clickhouse.com/docs/engines/database-engines) - [Table Engines](https://clickhouse.com/docs/engines/table-engines) - [Functions](https://clickhouse.com/docs/sql-reference/functions) - [Regular functions](https://clickhouse.com/docs/sql-reference/functions/regular-functions) - [Aggregate functions](https://clickhouse.com/docs/sql-reference/aggregate-functions) - [Table functions](https://clickhouse.com/docs/sql-reference/table-functions) - [Window functions](https://clickhouse.com/docs/sql-reference/window-functions) - [row\_number](https://clickhouse.com/docs/sql-reference/window-functions/row_number) - [first\_value](https://clickhouse.com/docs/sql-reference/window-functions/first_value) - [last\_value](https://clickhouse.com/docs/sql-reference/window-functions/last_value) - [nth\_value](https://clickhouse.com/docs/sql-reference/window-functions/nth_value) - [rank](https://clickhouse.com/docs/sql-reference/window-functions/rank) - [dense\_rank](https://clickhouse.com/docs/sql-reference/window-functions/dense_rank) - [percent\_rank](https://clickhouse.com/docs/sql-reference/window-functions/percent_rank) - [lag](https://clickhouse.com/docs/sql-reference/window-functions/lag) - [lagInFrame](https://clickhouse.com/docs/sql-reference/window-functions/lagInFrame) - [lead](https://clickhouse.com/docs/sql-reference/window-functions/lead) - [leadInFrame](https://clickhouse.com/docs/sql-reference/window-functions/leadInFrame) - [cume\_dist](https://clickhouse.com/docs/sql-reference/window-functions/cume_dist) - [Formats](https://clickhouse.com/docs/interfaces/formats) - [Data Lakes](https://clickhouse.com/docs/sql-reference/datalakes) - [Functions](https://clickhouse.com/docs/sql-reference/functions) - Window functions [Edit this page](https://github.com/ClickHouse/ClickHouse/tree/master/docs/en/sql-reference/window-functions/index.md) # Window functions Window functions let you perform calculations across a set of rows that are related to the current row. Some of the calculations that you can do are similar to those that can be done with an aggregate function, but a window function doesn't cause rows to be grouped into a single output - the individual rows are still returned. ## Standard window functions[​](https://clickhouse.com/docs/sql-reference/window-functions#standard-window-functions "Direct link to Standard window functions") ClickHouse supports the standard grammar for defining windows and window functions. The table below indicates whether a feature is currently supported. | Feature | Supported? | |---|---| | ad hoc window specification (`count(*) over (partition by id order by time desc)`) | βœ… | | expressions involving window functions, e.g. `(count(*) over ()) / 2)` | βœ… | | `WINDOW` clause (`select ... from table window w as (partition by id)`) | βœ… | | `ROWS` frame | βœ… | | `RANGE` frame | βœ… (the default) | | `INTERVAL` syntax for `DateTime` `RANGE OFFSET` frame | ❌ (specify the number of seconds instead (`RANGE` works with any numeric type).) | | `GROUPS` frame | ❌ | | Calculating aggregate functions over a frame (`sum(value) over (order by time)`) | βœ… (All aggregate functions are supported) | | `rank()`, `dense_rank()`, `row_number()` | βœ… Alias: `denseRank()` | | `percent_rank()` | βœ… Efficiently computes the relative standing of a value within a partition in a dataset. This function effectively replaces the more verbose and computationally intensive manual SQL calculation expressed as `ifNull((rank() OVER(PARTITION BY x ORDER BY y) - 1) / nullif(count(1) OVER(PARTITION BY x) - 1, 0), 0)` Alias: `percentRank()` | | `cume_dist()` | βœ… Computes the cumulative distribution of a value within a group of values. Returns the percentage of rows with values less than or equal to the current row's value. | | `lag/lead(value, offset)` | βœ… You can also use one of the following workarounds: 1) `any(value) over (.... rows between <offset> preceding and <offset> preceding)`, or `following` for `lead` 2) `lagInFrame/leadInFrame`, which are analogous, but respect the window frame. To get behavior identical to `lag/lead`, use `rows between unbounded preceding and unbounded following` | | ntile(buckets) | βœ… Specify window like, (partition by x order by y rows between unbounded preceding and unbounded following). | ## ClickHouse-specific window functions[​](https://clickhouse.com/docs/sql-reference/window-functions#clickhouse-specific-window-functions "Direct link to ClickHouse-specific window functions") There is also the following ClickHouse specific window function: ### nonNegativeDerivative(metric\_column, timestamp\_column\[, INTERVAL X UNITS\])[​](https://clickhouse.com/docs/sql-reference/window-functions#nonnegativederivativemetric_column-timestamp_column-interval-x-units "Direct link to nonNegativeDerivative(metric_column, timestamp_column[, INTERVAL X UNITS])") Finds non-negative derivative for given `metric_column` by `timestamp_column`. `INTERVAL` can be omitted, default is `INTERVAL 1 SECOND`. The computed value is the following for each row: - `0` for 1st row, - metric i βˆ’ metric i βˆ’ 1 timestamp i βˆ’ timestamp i βˆ’ 1 βˆ— interval {\\text{metric}\_i - \\text{metric}\_{i-1} \\over \\text{timestamp}\_i - \\text{timestamp}\_{i-1}} \* \\text{interval} timestampiβ€‹βˆ’timestampiβˆ’1​metriciβ€‹βˆ’metriciβˆ’1β€‹β€‹βˆ—interval for i t h i\_{th} ith​ row. ## Syntax[​](https://clickhouse.com/docs/sql-reference/window-functions#syntax "Direct link to Syntax") ``` aggregate_function (column_name) OVER ([[PARTITION BY grouping_column] [ORDER BY sorting_column] [ROWS or RANGE expression_to_bound_rows_within_the_group]] | [window_name]) FROM table_name WINDOW window_name as ([ [PARTITION BY grouping_column] [ORDER BY sorting_column] [ROWS or RANGE expression_to_bound_rows_within_the_group] ]) ``` - `PARTITION BY` - defines how to break a resultset into groups. - `ORDER BY` - defines how to order rows inside the group during calculation aggregate\_function. - `ROWS or RANGE` - defines bounds of a frame, aggregate\_function is calculated within a frame. - `WINDOW` - allows multiple expressions to use the same window definition. ``` PARTITION β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” <-- UNBOUNDED PRECEDING (BEGINNING of the PARTITION) β”‚ β”‚ β”‚ β”‚ β”‚=================β”‚ <-- N PRECEDING <─┐ β”‚ N ROWS β”‚ β”‚ F β”‚ Before CURRENT β”‚ β”‚ R β”‚~~~~~~~~~~~~~~~~~β”‚ <-- CURRENT ROW β”‚ A β”‚ M ROWS β”‚ β”‚ M β”‚ After CURRENT β”‚ β”‚ E β”‚=================β”‚ <-- M FOLLOWING <β”€β”˜ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ <--- UNBOUNDED FOLLOWING (END of the PARTITION) ``` ### Functions[​](https://clickhouse.com/docs/sql-reference/window-functions#functions "Direct link to Functions") These functions can be used only as a window function. - [`row_number()`](https://clickhouse.com/docs/sql-reference/window-functions/row_number) - Number the current row within its partition starting from 1. - [`first_value(x)`](https://clickhouse.com/docs/sql-reference/window-functions/first_value) - Return the first value evaluated within its ordered frame. - [`last_value(x)`](https://clickhouse.com/docs/sql-reference/window-functions/last_value) - Return the last value evaluated within its ordered frame. - [`nth_value(x, offset)`](https://clickhouse.com/docs/sql-reference/window-functions/nth_value) - Return the first non-NULL value evaluated against the nth row (offset) in its ordered frame. - [`rank()`](https://clickhouse.com/docs/sql-reference/window-functions/rank) - Rank the current row within its partition with gaps. - [`dense_rank()`](https://clickhouse.com/docs/sql-reference/window-functions/dense_rank) - Rank the current row within its partition without gaps. - [`lagInFrame(x)`](https://clickhouse.com/docs/sql-reference/window-functions/lagInFrame) - Return a value evaluated at the row that is at a specified physical offset row before the current row within the ordered frame. - [`leadInFrame(x)`](https://clickhouse.com/docs/sql-reference/window-functions/leadInFrame) - Return a value evaluated at the row that is offset rows after the current row within the ordered frame. ## Examples[​](https://clickhouse.com/docs/sql-reference/window-functions#examples "Direct link to Examples") Let's have a look at some examples of how window functions can be used. ### Numbering rows[​](https://clickhouse.com/docs/sql-reference/window-functions#numbering-rows "Direct link to Numbering rows") ``` CREATE TABLE salaries ( `team` String, `player` String, `salary` UInt32, `position` String ) Engine = Memory; INSERT INTO salaries FORMAT Values ('Port Elizabeth Barbarians', 'Gary Chen', 195000, 'F'), ('New Coreystad Archdukes', 'Charles Juarez', 190000, 'F'), ('Port Elizabeth Barbarians', 'Michael Stanley', 150000, 'D'), ('New Coreystad Archdukes', 'Scott Harrison', 150000, 'D'), ('Port Elizabeth Barbarians', 'Robert George', 195000, 'M'); ``` ``` SELECT player, salary, row_number() OVER (ORDER BY salary ASC) AS row FROM salaries; ``` ``` β”Œβ”€player──────────┬─salary─┬─row─┐ β”‚ Michael Stanley β”‚ 150000 β”‚ 1 β”‚ β”‚ Scott Harrison β”‚ 150000 β”‚ 2 β”‚ β”‚ Charles Juarez β”‚ 190000 β”‚ 3 β”‚ β”‚ Gary Chen β”‚ 195000 β”‚ 4 β”‚ β”‚ Robert George β”‚ 195000 β”‚ 5 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜ ``` ``` SELECT player, salary, row_number() OVER (ORDER BY salary ASC) AS row, rank() OVER (ORDER BY salary ASC) AS rank, dense_rank() OVER (ORDER BY salary ASC) AS denseRank FROM salaries; ``` ``` β”Œβ”€player──────────┬─salary─┬─row─┬─rank─┬─denseRank─┐ β”‚ Michael Stanley β”‚ 150000 β”‚ 1 β”‚ 1 β”‚ 1 β”‚ β”‚ Scott Harrison β”‚ 150000 β”‚ 2 β”‚ 1 β”‚ 1 β”‚ β”‚ Charles Juarez β”‚ 190000 β”‚ 3 β”‚ 3 β”‚ 2 β”‚ β”‚ Gary Chen β”‚ 195000 β”‚ 4 β”‚ 4 β”‚ 3 β”‚ β”‚ Robert George β”‚ 195000 β”‚ 5 β”‚ 4 β”‚ 3 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Aggregation functions[​](https://clickhouse.com/docs/sql-reference/window-functions#aggregation-functions "Direct link to Aggregation functions") Compare each player's salary to the average for their team. ``` SELECT player, salary, team, avg(salary) OVER (PARTITION BY team) AS teamAvg, salary - teamAvg AS diff FROM salaries; ``` ``` β”Œβ”€player──────────┬─salary─┬─team──────────────────────┬─teamAvg─┬───diff─┐ β”‚ Charles Juarez β”‚ 190000 β”‚ New Coreystad Archdukes β”‚ 170000 β”‚ 20000 β”‚ β”‚ Scott Harrison β”‚ 150000 β”‚ New Coreystad Archdukes β”‚ 170000 β”‚ -20000 β”‚ β”‚ Gary Chen β”‚ 195000 β”‚ Port Elizabeth Barbarians β”‚ 180000 β”‚ 15000 β”‚ β”‚ Michael Stanley β”‚ 150000 β”‚ Port Elizabeth Barbarians β”‚ 180000 β”‚ -30000 β”‚ β”‚ Robert George β”‚ 195000 β”‚ Port Elizabeth Barbarians β”‚ 180000 β”‚ 15000 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` Compare each player's salary to the maximum for their team. ``` SELECT player, salary, team, max(salary) OVER (PARTITION BY team) AS teamMax, salary - teamMax AS diff FROM salaries; ``` ``` β”Œβ”€player──────────┬─salary─┬─team──────────────────────┬─teamMax─┬───diff─┐ β”‚ Charles Juarez β”‚ 190000 β”‚ New Coreystad Archdukes β”‚ 190000 β”‚ 0 β”‚ β”‚ Scott Harrison β”‚ 150000 β”‚ New Coreystad Archdukes β”‚ 190000 β”‚ -40000 β”‚ β”‚ Gary Chen β”‚ 195000 β”‚ Port Elizabeth Barbarians β”‚ 195000 β”‚ 0 β”‚ β”‚ Michael Stanley β”‚ 150000 β”‚ Port Elizabeth Barbarians β”‚ 195000 β”‚ -45000 β”‚ β”‚ Robert George β”‚ 195000 β”‚ Port Elizabeth Barbarians β”‚ 195000 β”‚ 0 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Partitioning by column[​](https://clickhouse.com/docs/sql-reference/window-functions#partitioning-by-column "Direct link to Partitioning by column") ``` CREATE TABLE wf_partition ( `part_key` UInt64, `value` UInt64, `order` UInt64 ) ENGINE = Memory; INSERT INTO wf_partition FORMAT Values (1,1,1), (1,2,2), (1,3,3), (2,0,0), (3,0,0); SELECT part_key, value, order, groupArray(value) OVER (PARTITION BY part_key) AS frame_values FROM wf_partition ORDER BY part_key ASC, value ASC; β”Œβ”€part_key─┬─value─┬─order─┬─frame_values─┐ β”‚ 1 β”‚ 1 β”‚ 1 β”‚ [1,2,3] β”‚ <┐ β”‚ 1 β”‚ 2 β”‚ 2 β”‚ [1,2,3] β”‚ β”‚ 1-st group β”‚ 1 β”‚ 3 β”‚ 3 β”‚ [1,2,3] β”‚ <β”˜ β”‚ 2 β”‚ 0 β”‚ 0 β”‚ [0] β”‚ <- 2-nd group β”‚ 3 β”‚ 0 β”‚ 0 β”‚ [0] β”‚ <- 3-d group β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Frame bounding[​](https://clickhouse.com/docs/sql-reference/window-functions#frame-bounding "Direct link to Frame bounding") ``` CREATE TABLE wf_frame ( `part_key` UInt64, `value` UInt64, `order` UInt64 ) ENGINE = Memory; INSERT INTO wf_frame FORMAT Values (1,1,1), (1,2,2), (1,3,3), (1,4,4), (1,5,5); ``` ``` -- Frame is bounded by bounds of a partition (BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) SELECT part_key, value, order, groupArray(value) OVER ( PARTITION BY part_key ORDER BY order ASC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) AS frame_values FROM wf_frame ORDER BY part_key ASC, value ASC; β”Œβ”€part_key─┬─value─┬─order─┬─frame_values─┐ β”‚ 1 β”‚ 1 β”‚ 1 β”‚ [1,2,3,4,5] β”‚ β”‚ 1 β”‚ 2 β”‚ 2 β”‚ [1,2,3,4,5] β”‚ β”‚ 1 β”‚ 3 β”‚ 3 β”‚ [1,2,3,4,5] β”‚ β”‚ 1 β”‚ 4 β”‚ 4 β”‚ [1,2,3,4,5] β”‚ β”‚ 1 β”‚ 5 β”‚ 5 β”‚ [1,2,3,4,5] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ``` -- short form - no bound expression, no order by, -- an equalent of `ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING` SELECT part_key, value, order, groupArray(value) OVER (PARTITION BY part_key) AS frame_values_short, groupArray(value) OVER (PARTITION BY part_key ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) AS frame_values FROM wf_frame ORDER BY part_key ASC, value ASC; β”Œβ”€part_key─┬─value─┬─order─┬─frame_values_short─┬─frame_values─┐ β”‚ 1 β”‚ 1 β”‚ 1 β”‚ [1,2,3,4,5] β”‚ [1,2,3,4,5] β”‚ β”‚ 1 β”‚ 2 β”‚ 2 β”‚ [1,2,3,4,5] β”‚ [1,2,3,4,5] β”‚ β”‚ 1 β”‚ 3 β”‚ 3 β”‚ [1,2,3,4,5] β”‚ [1,2,3,4,5] β”‚ β”‚ 1 β”‚ 4 β”‚ 4 β”‚ [1,2,3,4,5] β”‚ [1,2,3,4,5] β”‚ β”‚ 1 β”‚ 5 β”‚ 5 β”‚ [1,2,3,4,5] β”‚ [1,2,3,4,5] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ``` -- frame is bounded by the beginning of a partition and the current row SELECT part_key, value, order, groupArray(value) OVER ( PARTITION BY part_key ORDER BY order ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS frame_values FROM wf_frame ORDER BY part_key ASC, value ASC; β”Œβ”€part_key─┬─value─┬─order─┬─frame_values─┐ β”‚ 1 β”‚ 1 β”‚ 1 β”‚ [1] β”‚ β”‚ 1 β”‚ 2 β”‚ 2 β”‚ [1,2] β”‚ β”‚ 1 β”‚ 3 β”‚ 3 β”‚ [1,2,3] β”‚ β”‚ 1 β”‚ 4 β”‚ 4 β”‚ [1,2,3,4] β”‚ β”‚ 1 β”‚ 5 β”‚ 5 β”‚ [1,2,3,4,5] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ``` -- short form (frame is bounded by the beginning of a partition and the current row) -- an equalent of `ORDER BY order ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW` SELECT part_key, value, order, groupArray(value) OVER (PARTITION BY part_key ORDER BY order ASC) AS frame_values_short, groupArray(value) OVER (PARTITION BY part_key ORDER BY order ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS frame_values FROM wf_frame ORDER BY part_key ASC, value ASC; β”Œβ”€part_key─┬─value─┬─order─┬─frame_values_short─┬─frame_values─┐ β”‚ 1 β”‚ 1 β”‚ 1 β”‚ [1] β”‚ [1] β”‚ β”‚ 1 β”‚ 2 β”‚ 2 β”‚ [1,2] β”‚ [1,2] β”‚ β”‚ 1 β”‚ 3 β”‚ 3 β”‚ [1,2,3] β”‚ [1,2,3] β”‚ β”‚ 1 β”‚ 4 β”‚ 4 β”‚ [1,2,3,4] β”‚ [1,2,3,4] β”‚ β”‚ 1 β”‚ 5 β”‚ 5 β”‚ [1,2,3,4,5] β”‚ [1,2,3,4,5] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ``` -- frame is bounded by the beginning of a partition and the current row, but order is backward SELECT part_key, value, order, groupArray(value) OVER (PARTITION BY part_key ORDER BY order DESC) AS frame_values FROM wf_frame ORDER BY part_key ASC, value ASC; β”Œβ”€part_key─┬─value─┬─order─┬─frame_values─┐ β”‚ 1 β”‚ 1 β”‚ 1 β”‚ [5,4,3,2,1] β”‚ β”‚ 1 β”‚ 2 β”‚ 2 β”‚ [5,4,3,2] β”‚ β”‚ 1 β”‚ 3 β”‚ 3 β”‚ [5,4,3] β”‚ β”‚ 1 β”‚ 4 β”‚ 4 β”‚ [5,4] β”‚ β”‚ 1 β”‚ 5 β”‚ 5 β”‚ [5] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ``` -- sliding frame - 1 PRECEDING ROW AND CURRENT ROW SELECT part_key, value, order, groupArray(value) OVER ( PARTITION BY part_key ORDER BY order ASC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW ) AS frame_values FROM wf_frame ORDER BY part_key ASC, value ASC; β”Œβ”€part_key─┬─value─┬─order─┬─frame_values─┐ β”‚ 1 β”‚ 1 β”‚ 1 β”‚ [1] β”‚ β”‚ 1 β”‚ 2 β”‚ 2 β”‚ [1,2] β”‚ β”‚ 1 β”‚ 3 β”‚ 3 β”‚ [2,3] β”‚ β”‚ 1 β”‚ 4 β”‚ 4 β”‚ [3,4] β”‚ β”‚ 1 β”‚ 5 β”‚ 5 β”‚ [4,5] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ``` -- sliding frame - ROWS BETWEEN 1 PRECEDING AND UNBOUNDED FOLLOWING SELECT part_key, value, order, groupArray(value) OVER ( PARTITION BY part_key ORDER BY order ASC ROWS BETWEEN 1 PRECEDING AND UNBOUNDED FOLLOWING ) AS frame_values FROM wf_frame ORDER BY part_key ASC, value ASC; β”Œβ”€part_key─┬─value─┬─order─┬─frame_values─┐ β”‚ 1 β”‚ 1 β”‚ 1 β”‚ [1,2,3,4,5] β”‚ β”‚ 1 β”‚ 2 β”‚ 2 β”‚ [1,2,3,4,5] β”‚ β”‚ 1 β”‚ 3 β”‚ 3 β”‚ [2,3,4,5] β”‚ β”‚ 1 β”‚ 4 β”‚ 4 β”‚ [3,4,5] β”‚ β”‚ 1 β”‚ 5 β”‚ 5 β”‚ [4,5] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ``` -- row_number does not respect the frame, so rn_1 = rn_2 = rn_3 != rn_4 SELECT part_key, value, order, groupArray(value) OVER w1 AS frame_values, row_number() OVER w1 AS rn_1, sum(1) OVER w1 AS rn_2, row_number() OVER w2 AS rn_3, sum(1) OVER w2 AS rn_4 FROM wf_frame WINDOW w1 AS (PARTITION BY part_key ORDER BY order DESC), w2 AS ( PARTITION BY part_key ORDER BY order DESC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW ) ORDER BY part_key ASC, value ASC; β”Œβ”€part_key─┬─value─┬─order─┬─frame_values─┬─rn_1─┬─rn_2─┬─rn_3─┬─rn_4─┐ β”‚ 1 β”‚ 1 β”‚ 1 β”‚ [5,4,3,2,1] β”‚ 5 β”‚ 5 β”‚ 5 β”‚ 2 β”‚ β”‚ 1 β”‚ 2 β”‚ 2 β”‚ [5,4,3,2] β”‚ 4 β”‚ 4 β”‚ 4 β”‚ 2 β”‚ β”‚ 1 β”‚ 3 β”‚ 3 β”‚ [5,4,3] β”‚ 3 β”‚ 3 β”‚ 3 β”‚ 2 β”‚ β”‚ 1 β”‚ 4 β”‚ 4 β”‚ [5,4] β”‚ 2 β”‚ 2 β”‚ 2 β”‚ 2 β”‚ β”‚ 1 β”‚ 5 β”‚ 5 β”‚ [5] β”‚ 1 β”‚ 1 β”‚ 1 β”‚ 1 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”˜ ``` ``` -- first_value and last_value respect the frame SELECT groupArray(value) OVER w1 AS frame_values_1, first_value(value) OVER w1 AS first_value_1, last_value(value) OVER w1 AS last_value_1, groupArray(value) OVER w2 AS frame_values_2, first_value(value) OVER w2 AS first_value_2, last_value(value) OVER w2 AS last_value_2 FROM wf_frame WINDOW w1 AS (PARTITION BY part_key ORDER BY order ASC), w2 AS (PARTITION BY part_key ORDER BY order ASC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) ORDER BY part_key ASC, value ASC; β”Œβ”€frame_values_1─┬─first_value_1─┬─last_value_1─┬─frame_values_2─┬─first_value_2─┬─last_value_2─┐ β”‚ [1] β”‚ 1 β”‚ 1 β”‚ [1] β”‚ 1 β”‚ 1 β”‚ β”‚ [1,2] β”‚ 1 β”‚ 2 β”‚ [1,2] β”‚ 1 β”‚ 2 β”‚ β”‚ [1,2,3] β”‚ 1 β”‚ 3 β”‚ [2,3] β”‚ 2 β”‚ 3 β”‚ β”‚ [1,2,3,4] β”‚ 1 β”‚ 4 β”‚ [3,4] β”‚ 3 β”‚ 4 β”‚ β”‚ [1,2,3,4,5] β”‚ 1 β”‚ 5 β”‚ [4,5] β”‚ 4 β”‚ 5 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ``` -- second value within the frame SELECT groupArray(value) OVER w1 AS frame_values_1, nth_value(value, 2) OVER w1 AS second_value FROM wf_frame WINDOW w1 AS (PARTITION BY part_key ORDER BY order ASC ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) ORDER BY part_key ASC, value ASC; β”Œβ”€frame_values_1─┬─second_value─┐ β”‚ [1] β”‚ 0 β”‚ β”‚ [1,2] β”‚ 2 β”‚ β”‚ [1,2,3] β”‚ 2 β”‚ β”‚ [1,2,3,4] β”‚ 2 β”‚ β”‚ [2,3,4,5] β”‚ 3 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ``` -- second value within the frame + Null for missing values SELECT groupArray(value) OVER w1 AS frame_values_1, nth_value(toNullable(value), 2) OVER w1 AS second_value FROM wf_frame WINDOW w1 AS (PARTITION BY part_key ORDER BY order ASC ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) ORDER BY part_key ASC, value ASC; β”Œβ”€frame_values_1─┬─second_value─┐ β”‚ [1] β”‚ ᴺᡁᴸᴸ β”‚ β”‚ [1,2] β”‚ 2 β”‚ β”‚ [1,2,3] β”‚ 2 β”‚ β”‚ [1,2,3,4] β”‚ 2 β”‚ β”‚ [2,3,4,5] β”‚ 3 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ## Real world examples[​](https://clickhouse.com/docs/sql-reference/window-functions#real-world-examples "Direct link to Real world examples") The following examples solve common real-world problems. ### Maximum/total salary per department[​](https://clickhouse.com/docs/sql-reference/window-functions#maximumtotal-salary-per-department "Direct link to Maximum/total salary per department") ``` CREATE TABLE employees ( `department` String, `employee_name` String, `salary` Float ) ENGINE = Memory; INSERT INTO employees FORMAT Values ('Finance', 'Jonh', 200), ('Finance', 'Joan', 210), ('Finance', 'Jean', 505), ('IT', 'Tim', 200), ('IT', 'Anna', 300), ('IT', 'Elen', 500); ``` ``` SELECT department, employee_name AS emp, salary, max_salary_per_dep, total_salary_per_dep, round((salary / total_salary_per_dep) * 100, 2) AS `share_per_dep(%)` FROM ( SELECT department, employee_name, salary, max(salary) OVER wndw AS max_salary_per_dep, sum(salary) OVER wndw AS total_salary_per_dep FROM employees WINDOW wndw AS ( PARTITION BY department ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) ORDER BY department ASC, employee_name ASC ); β”Œβ”€department─┬─emp──┬─salary─┬─max_salary_per_dep─┬─total_salary_per_dep─┬─share_per_dep(%)─┐ β”‚ Finance β”‚ Jean β”‚ 505 β”‚ 505 β”‚ 915 β”‚ 55.19 β”‚ β”‚ Finance β”‚ Joan β”‚ 210 β”‚ 505 β”‚ 915 β”‚ 22.95 β”‚ β”‚ Finance β”‚ Jonh β”‚ 200 β”‚ 505 β”‚ 915 β”‚ 21.86 β”‚ β”‚ IT β”‚ Anna β”‚ 300 β”‚ 500 β”‚ 1000 β”‚ 30 β”‚ β”‚ IT β”‚ Elen β”‚ 500 β”‚ 500 β”‚ 1000 β”‚ 50 β”‚ β”‚ IT β”‚ Tim β”‚ 200 β”‚ 500 β”‚ 1000 β”‚ 20 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Cumulative sum[​](https://clickhouse.com/docs/sql-reference/window-functions#cumulative-sum "Direct link to Cumulative sum") ``` CREATE TABLE warehouse ( `item` String, `ts` DateTime, `value` Float ) ENGINE = Memory INSERT INTO warehouse VALUES ('sku38', '2020-01-01', 9), ('sku38', '2020-02-01', 1), ('sku38', '2020-03-01', -4), ('sku1', '2020-01-01', 1), ('sku1', '2020-02-01', 1), ('sku1', '2020-03-01', 1); ``` ``` SELECT item, ts, value, sum(value) OVER (PARTITION BY item ORDER BY ts ASC) AS stock_balance FROM warehouse ORDER BY item ASC, ts ASC; β”Œβ”€item──┬──────────────────ts─┬─value─┬─stock_balance─┐ β”‚ sku1 β”‚ 2020-01-01 00:00:00 β”‚ 1 β”‚ 1 β”‚ β”‚ sku1 β”‚ 2020-02-01 00:00:00 β”‚ 1 β”‚ 2 β”‚ β”‚ sku1 β”‚ 2020-03-01 00:00:00 β”‚ 1 β”‚ 3 β”‚ β”‚ sku38 β”‚ 2020-01-01 00:00:00 β”‚ 9 β”‚ 9 β”‚ β”‚ sku38 β”‚ 2020-02-01 00:00:00 β”‚ 1 β”‚ 10 β”‚ β”‚ sku38 β”‚ 2020-03-01 00:00:00 β”‚ -4 β”‚ 6 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Moving / sliding average (per 3 rows)[​](https://clickhouse.com/docs/sql-reference/window-functions#moving--sliding-average-per-3-rows "Direct link to Moving / sliding average (per 3 rows)") ``` CREATE TABLE sensors ( `metric` String, `ts` DateTime, `value` Float ) ENGINE = Memory; insert into sensors values('cpu_temp', '2020-01-01 00:00:00', 87), ('cpu_temp', '2020-01-01 00:00:01', 77), ('cpu_temp', '2020-01-01 00:00:02', 93), ('cpu_temp', '2020-01-01 00:00:03', 87), ('cpu_temp', '2020-01-01 00:00:04', 87), ('cpu_temp', '2020-01-01 00:00:05', 87), ('cpu_temp', '2020-01-01 00:00:06', 87), ('cpu_temp', '2020-01-01 00:00:07', 87); ``` ``` SELECT metric, ts, value, avg(value) OVER ( PARTITION BY metric ORDER BY ts ASC ROWS BETWEEN 2 PRECEDING AND CURRENT ROW ) AS moving_avg_temp FROM sensors ORDER BY metric ASC, ts ASC; β”Œβ”€metric───┬──────────────────ts─┬─value─┬───moving_avg_temp─┐ β”‚ cpu_temp β”‚ 2020-01-01 00:00:00 β”‚ 87 β”‚ 87 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:00:01 β”‚ 77 β”‚ 82 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:00:02 β”‚ 93 β”‚ 85.66666666666667 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:00:03 β”‚ 87 β”‚ 85.66666666666667 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:00:04 β”‚ 87 β”‚ 89 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:00:05 β”‚ 87 β”‚ 87 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:00:06 β”‚ 87 β”‚ 87 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:00:07 β”‚ 87 β”‚ 87 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Moving / sliding average (per 10 seconds)[​](https://clickhouse.com/docs/sql-reference/window-functions#moving--sliding-average-per-10-seconds "Direct link to Moving / sliding average (per 10 seconds)") ``` SELECT metric, ts, value, avg(value) OVER (PARTITION BY metric ORDER BY ts RANGE BETWEEN 10 PRECEDING AND CURRENT ROW) AS moving_avg_10_seconds_temp FROM sensors ORDER BY metric ASC, ts ASC; β”Œβ”€metric───┬──────────────────ts─┬─value─┬─moving_avg_10_seconds_temp─┐ β”‚ cpu_temp β”‚ 2020-01-01 00:00:00 β”‚ 87 β”‚ 87 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:01:10 β”‚ 77 β”‚ 77 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:02:20 β”‚ 93 β”‚ 93 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:03:30 β”‚ 87 β”‚ 87 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:04:40 β”‚ 87 β”‚ 87 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:05:50 β”‚ 87 β”‚ 87 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:06:00 β”‚ 87 β”‚ 87 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:07:10 β”‚ 87 β”‚ 87 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Moving / sliding average (per 10 days)[​](https://clickhouse.com/docs/sql-reference/window-functions#moving--sliding-average-per-10-days "Direct link to Moving / sliding average (per 10 days)") Temperature is stored with second precision, but using `Range` and `ORDER BY toDate(ts)` we form a frame with the size of 10 units, and because of `toDate(ts)` the unit is a day. ``` CREATE TABLE sensors ( `metric` String, `ts` DateTime, `value` Float ) ENGINE = Memory; insert into sensors values('ambient_temp', '2020-01-01 00:00:00', 16), ('ambient_temp', '2020-01-01 12:00:00', 16), ('ambient_temp', '2020-01-02 11:00:00', 9), ('ambient_temp', '2020-01-02 12:00:00', 9), ('ambient_temp', '2020-02-01 10:00:00', 10), ('ambient_temp', '2020-02-01 12:00:00', 10), ('ambient_temp', '2020-02-10 12:00:00', 12), ('ambient_temp', '2020-02-10 13:00:00', 12), ('ambient_temp', '2020-02-20 12:00:01', 16), ('ambient_temp', '2020-03-01 12:00:00', 16), ('ambient_temp', '2020-03-01 12:00:00', 16), ('ambient_temp', '2020-03-01 12:00:00', 16); ``` ``` SELECT metric, ts, value, round(avg(value) OVER (PARTITION BY metric ORDER BY toDate(ts) RANGE BETWEEN 10 PRECEDING AND CURRENT ROW),2) AS moving_avg_10_days_temp FROM sensors ORDER BY metric ASC, ts ASC; β”Œβ”€metric───────┬──────────────────ts─┬─value─┬─moving_avg_10_days_temp─┐ β”‚ ambient_temp β”‚ 2020-01-01 00:00:00 β”‚ 16 β”‚ 16 β”‚ β”‚ ambient_temp β”‚ 2020-01-01 12:00:00 β”‚ 16 β”‚ 16 β”‚ β”‚ ambient_temp β”‚ 2020-01-02 11:00:00 β”‚ 9 β”‚ 12.5 β”‚ β”‚ ambient_temp β”‚ 2020-01-02 12:00:00 β”‚ 9 β”‚ 12.5 β”‚ β”‚ ambient_temp β”‚ 2020-02-01 10:00:00 β”‚ 10 β”‚ 10 β”‚ β”‚ ambient_temp β”‚ 2020-02-01 12:00:00 β”‚ 10 β”‚ 10 β”‚ β”‚ ambient_temp β”‚ 2020-02-10 12:00:00 β”‚ 12 β”‚ 11 β”‚ β”‚ ambient_temp β”‚ 2020-02-10 13:00:00 β”‚ 12 β”‚ 11 β”‚ β”‚ ambient_temp β”‚ 2020-02-20 12:00:01 β”‚ 16 β”‚ 13.33 β”‚ β”‚ ambient_temp β”‚ 2020-03-01 12:00:00 β”‚ 16 β”‚ 16 β”‚ β”‚ ambient_temp β”‚ 2020-03-01 12:00:00 β”‚ 16 β”‚ 16 β”‚ β”‚ ambient_temp β”‚ 2020-03-01 12:00:00 β”‚ 16 β”‚ 16 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ## References[​](https://clickhouse.com/docs/sql-reference/window-functions#references "Direct link to References") ### GitHub Issues[​](https://clickhouse.com/docs/sql-reference/window-functions#github-issues "Direct link to GitHub Issues") The roadmap for the initial support of window functions is [in this issue](https://github.com/ClickHouse/ClickHouse/issues/18097). All GitHub issues related to window functions have the [comp-window-functions](https://github.com/ClickHouse/ClickHouse/labels/comp-window-functions) tag. ### Tests[​](https://clickhouse.com/docs/sql-reference/window-functions#tests "Direct link to Tests") These tests contain the examples of the currently supported grammar: <https://github.com/ClickHouse/ClickHouse/blob/master/tests/performance/window_functions.xml> <https://github.com/ClickHouse/ClickHouse/blob/master/tests/queries/0_stateless/01591_window_functions.sql> ### Postgres Docs[​](https://clickhouse.com/docs/sql-reference/window-functions#postgres-docs "Direct link to Postgres Docs") <https://www.postgresql.org/docs/current/sql-select.html#SQL-WINDOW> <https://www.postgresql.org/docs/devel/sql-expressions.html#SYNTAX-WINDOW-FUNCTIONS> <https://www.postgresql.org/docs/devel/functions-window.html> <https://www.postgresql.org/docs/devel/tutorial-window.html> ### MySQL Docs[​](https://clickhouse.com/docs/sql-reference/window-functions#mysql-docs "Direct link to MySQL Docs") <https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html> <https://dev.mysql.com/doc/refman/8.0/en/window-functions-usage.html> <https://dev.mysql.com/doc/refman/8.0/en/window-functions-frames.html> ## Related Content[​](https://clickhouse.com/docs/sql-reference/window-functions#related-content "Direct link to Related Content") - Blog: [Working with time series data in ClickHouse](https://clickhouse.com/blog/working-with-time-series-data-and-functions-ClickHouse) - Blog: [Window and array functions for Git commit sequences](https://clickhouse.com/blog/clickhouse-window-array-functions-git-commits) - Blog: [Getting Data Into ClickHouse - Part 3 - Using S3](https://clickhouse.com/blog/getting-data-into-clickhouse-part-3-s3) [Previous loop](https://clickhouse.com/docs/sql-reference/table-functions/loop) [Next row\_number](https://clickhouse.com/docs/sql-reference/window-functions/row_number) - [Standard window functions](https://clickhouse.com/docs/sql-reference/window-functions#standard-window-functions) - [ClickHouse-specific window functions](https://clickhouse.com/docs/sql-reference/window-functions#clickhouse-specific-window-functions) - [nonNegativeDerivative(metric\_column, timestamp\_column\[, INTERVAL X UNITS\])](https://clickhouse.com/docs/sql-reference/window-functions#nonnegativederivativemetric_column-timestamp_column-interval-x-units) - [Syntax](https://clickhouse.com/docs/sql-reference/window-functions#syntax) - [Functions](https://clickhouse.com/docs/sql-reference/window-functions#functions) - [Examples](https://clickhouse.com/docs/sql-reference/window-functions#examples) - [Numbering rows](https://clickhouse.com/docs/sql-reference/window-functions#numbering-rows) - [Aggregation functions](https://clickhouse.com/docs/sql-reference/window-functions#aggregation-functions) - [Partitioning by column](https://clickhouse.com/docs/sql-reference/window-functions#partitioning-by-column) - [Frame bounding](https://clickhouse.com/docs/sql-reference/window-functions#frame-bounding) - [Real world examples](https://clickhouse.com/docs/sql-reference/window-functions#real-world-examples) - [Maximum/total salary per department](https://clickhouse.com/docs/sql-reference/window-functions#maximumtotal-salary-per-department) - [Cumulative sum](https://clickhouse.com/docs/sql-reference/window-functions#cumulative-sum) - [Moving / sliding average (per 3 rows)](https://clickhouse.com/docs/sql-reference/window-functions#moving--sliding-average-per-3-rows) - [Moving / sliding average (per 10 seconds)](https://clickhouse.com/docs/sql-reference/window-functions#moving--sliding-average-per-10-seconds) - [Moving / sliding average (per 10 days)](https://clickhouse.com/docs/sql-reference/window-functions#moving--sliding-average-per-10-days) - [References](https://clickhouse.com/docs/sql-reference/window-functions#references) - [GitHub Issues](https://clickhouse.com/docs/sql-reference/window-functions#github-issues) - [Tests](https://clickhouse.com/docs/sql-reference/window-functions#tests) - [Postgres Docs](https://clickhouse.com/docs/sql-reference/window-functions#postgres-docs) - [MySQL Docs](https://clickhouse.com/docs/sql-reference/window-functions#mysql-docs) - [Related Content](https://clickhouse.com/docs/sql-reference/window-functions#related-content) Was this page helpful? ###### Try ClickHouse Cloud for FREE Separation of storage and compute, automatic scaling, built-in SQL console, and lots more. \$300 in free credits when signing up. [Try it for Free](https://console.clickhouse.cloud/signUp?loc=doc-card-banner&glxid=ec987698-9313-4186-9781-be5fd1b64e13&pagePath=%2Fdocs%2Fsql-reference%2Fwindow-functions&origPath=%2Fdocs%2Fsql-reference%2Fwindow-functions&utm_ga=GA1.1.1971283203.1775876958) Β© 2016–2026 ClickHouse, Inc. [Trademark](https://clickhouse.com/legal/trademark-policy)Β·[Privacy](https://clickhouse.com/legal/privacy-policy)Β·[Security](https://trust.clickhouse.com/)Β·[Terms of Service](https://clickhouse.com/legal/agreements/terms-of-service) ![](https://static.scarf.sh/a.png?x-pxid=e6377503-591b-4886-9398-e69c7fee0b91) Β© 2016–2026 ClickHouse, Inc. [Trademark](https://clickhouse.com/legal/trademark-policy)Β·[Privacy](https://clickhouse.com/legal/privacy-policy)Β·[Security](https://trust.clickhouse.com/)Β·[Terms of Service](https://clickhouse.com/legal/agreements/terms-of-service) ![](https://static.scarf.sh/a.png?x-pxid=e6377503-591b-4886-9398-e69c7fee0b91) [![ClickHouse](https://clickhouse.com/docs/img/ch_logo_docs.svg)](https://clickhouse.com/) EN - Get startedβ–Ό - Cloudβ–Ό - Manage dataβ–Ό - Server adminβ–Ό - Referenceβ–Ό - Integrationsβ–Ό - ClickStackβ–Ό - chDBβ–Ό - Aboutβ–Ό [![ClickHouse](https://clickhouse.com/docs/img/ch_logo_docs.svg)](https://clickhouse.com/) EN main-menu - Introductionβ–Ό - [Syntax](https://clickhouse.com/docs/sql-reference/syntax) - [Input and Output Formats](https://clickhouse.com/docs/sql-reference/formats) - Data typesβ–Ό - Statementsβ–Ό - Operatorsβ–Ό - Enginesβ–Ό - Functionsβ–Ό - Formatsβ–Ό - [Data Lakes](https://clickhouse.com/docs/sql-reference/datalakes)
Readable Markdown
Window functions let you perform calculations across a set of rows that are related to the current row. Some of the calculations that you can do are similar to those that can be done with an aggregate function, but a window function doesn't cause rows to be grouped into a single output - the individual rows are still returned. ## Standard window functions[​](https://clickhouse.com/docs/sql-reference/window-functions#standard-window-functions "Direct link to Standard window functions") ClickHouse supports the standard grammar for defining windows and window functions. The table below indicates whether a feature is currently supported. | Feature | Supported? | |---|---| | ad hoc window specification (`count(*) over (partition by id order by time desc)`) | βœ… | | expressions involving window functions, e.g. `(count(*) over ()) / 2)` | βœ… | | `WINDOW` clause (`select ... from table window w as (partition by id)`) | βœ… | | `ROWS` frame | βœ… | | `RANGE` frame | βœ… (the default) | | `INTERVAL` syntax for `DateTime` `RANGE OFFSET` frame | ❌ (specify the number of seconds instead (`RANGE` works with any numeric type).) | | `GROUPS` frame | ❌ | | Calculating aggregate functions over a frame (`sum(value) over (order by time)`) | βœ… (All aggregate functions are supported) | | `rank()`, `dense_rank()`, `row_number()` | βœ… Alias: `denseRank()` | | `percent_rank()` | βœ… Efficiently computes the relative standing of a value within a partition in a dataset. This function effectively replaces the more verbose and computationally intensive manual SQL calculation expressed as `ifNull((rank() OVER(PARTITION BY x ORDER BY y) - 1) / nullif(count(1) OVER(PARTITION BY x) - 1, 0), 0)` Alias: `percentRank()` | | `cume_dist()` | βœ… Computes the cumulative distribution of a value within a group of values. Returns the percentage of rows with values less than or equal to the current row's value. | | `lag/lead(value, offset)` | βœ… You can also use one of the following workarounds: 1) `any(value) over (.... rows between <offset> preceding and <offset> preceding)`, or `following` for `lead` 2) `lagInFrame/leadInFrame`, which are analogous, but respect the window frame. To get behavior identical to `lag/lead`, use `rows between unbounded preceding and unbounded following` | | ntile(buckets) | βœ… Specify window like, (partition by x order by y rows between unbounded preceding and unbounded following). | ## ClickHouse-specific window functions[​](https://clickhouse.com/docs/sql-reference/window-functions#clickhouse-specific-window-functions "Direct link to ClickHouse-specific window functions") There is also the following ClickHouse specific window function: ### nonNegativeDerivative(metric\_column, timestamp\_column\[, INTERVAL X UNITS\])[​](https://clickhouse.com/docs/sql-reference/window-functions#nonnegativederivativemetric_column-timestamp_column-interval-x-units "Direct link to nonNegativeDerivative(metric_column, timestamp_column[, INTERVAL X UNITS])") Finds non-negative derivative for given `metric_column` by `timestamp_column`. `INTERVAL` can be omitted, default is `INTERVAL 1 SECOND`. The computed value is the following for each row: - `0` for 1st row, - metric i βˆ’ metric i βˆ’ 1 timestamp i βˆ’ timestamp i βˆ’ 1 βˆ— interval {\\text{metric}\_i - \\text{metric}\_{i-1} \\over \\text{timestamp}\_i - \\text{timestamp}\_{i-1}} \* \\text{interval} for i t h i\_{th} row. ## Syntax[​](https://clickhouse.com/docs/sql-reference/window-functions#syntax "Direct link to Syntax") ``` aggregate_function (column_name) OVER ([[PARTITION BY grouping_column] [ORDER BY sorting_column] [ROWS or RANGE expression_to_bound_rows_within_the_group]] | [window_name]) FROM table_name WINDOW window_name as ([ [PARTITION BY grouping_column] [ORDER BY sorting_column] [ROWS or RANGE expression_to_bound_rows_within_the_group] ]) ``` - `PARTITION BY` - defines how to break a resultset into groups. - `ORDER BY` - defines how to order rows inside the group during calculation aggregate\_function. - `ROWS or RANGE` - defines bounds of a frame, aggregate\_function is calculated within a frame. - `WINDOW` - allows multiple expressions to use the same window definition. ``` PARTITION β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” <-- UNBOUNDED PRECEDING (BEGINNING of the PARTITION) β”‚ β”‚ β”‚ β”‚ β”‚=================β”‚ <-- N PRECEDING <─┐ β”‚ N ROWS β”‚ β”‚ F β”‚ Before CURRENT β”‚ β”‚ R β”‚~~~~~~~~~~~~~~~~~β”‚ <-- CURRENT ROW β”‚ A β”‚ M ROWS β”‚ β”‚ M β”‚ After CURRENT β”‚ β”‚ E β”‚=================β”‚ <-- M FOLLOWING <β”€β”˜ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ <--- UNBOUNDED FOLLOWING (END of the PARTITION) ``` ### Functions[​](https://clickhouse.com/docs/sql-reference/window-functions#functions "Direct link to Functions") These functions can be used only as a window function. - [`row_number()`](https://clickhouse.com/docs/sql-reference/window-functions/row_number) - Number the current row within its partition starting from 1. - [`first_value(x)`](https://clickhouse.com/docs/sql-reference/window-functions/first_value) - Return the first value evaluated within its ordered frame. - [`last_value(x)`](https://clickhouse.com/docs/sql-reference/window-functions/last_value) - Return the last value evaluated within its ordered frame. - [`nth_value(x, offset)`](https://clickhouse.com/docs/sql-reference/window-functions/nth_value) - Return the first non-NULL value evaluated against the nth row (offset) in its ordered frame. - [`rank()`](https://clickhouse.com/docs/sql-reference/window-functions/rank) - Rank the current row within its partition with gaps. - [`dense_rank()`](https://clickhouse.com/docs/sql-reference/window-functions/dense_rank) - Rank the current row within its partition without gaps. - [`lagInFrame(x)`](https://clickhouse.com/docs/sql-reference/window-functions/lagInFrame) - Return a value evaluated at the row that is at a specified physical offset row before the current row within the ordered frame. - [`leadInFrame(x)`](https://clickhouse.com/docs/sql-reference/window-functions/leadInFrame) - Return a value evaluated at the row that is offset rows after the current row within the ordered frame. ## Examples[​](https://clickhouse.com/docs/sql-reference/window-functions#examples "Direct link to Examples") Let's have a look at some examples of how window functions can be used. ### Numbering rows[​](https://clickhouse.com/docs/sql-reference/window-functions#numbering-rows "Direct link to Numbering rows") ``` CREATE TABLE salaries ( `team` String, `player` String, `salary` UInt32, `position` String ) Engine = Memory; INSERT INTO salaries FORMAT Values ('Port Elizabeth Barbarians', 'Gary Chen', 195000, 'F'), ('New Coreystad Archdukes', 'Charles Juarez', 190000, 'F'), ('Port Elizabeth Barbarians', 'Michael Stanley', 150000, 'D'), ('New Coreystad Archdukes', 'Scott Harrison', 150000, 'D'), ('Port Elizabeth Barbarians', 'Robert George', 195000, 'M'); ``` ``` SELECT player, salary, row_number() OVER (ORDER BY salary ASC) AS row FROM salaries; ``` ``` β”Œβ”€player──────────┬─salary─┬─row─┐ β”‚ Michael Stanley β”‚ 150000 β”‚ 1 β”‚ β”‚ Scott Harrison β”‚ 150000 β”‚ 2 β”‚ β”‚ Charles Juarez β”‚ 190000 β”‚ 3 β”‚ β”‚ Gary Chen β”‚ 195000 β”‚ 4 β”‚ β”‚ Robert George β”‚ 195000 β”‚ 5 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜ ``` ``` SELECT player, salary, row_number() OVER (ORDER BY salary ASC) AS row, rank() OVER (ORDER BY salary ASC) AS rank, dense_rank() OVER (ORDER BY salary ASC) AS denseRank FROM salaries; ``` ``` β”Œβ”€player──────────┬─salary─┬─row─┬─rank─┬─denseRank─┐ β”‚ Michael Stanley β”‚ 150000 β”‚ 1 β”‚ 1 β”‚ 1 β”‚ β”‚ Scott Harrison β”‚ 150000 β”‚ 2 β”‚ 1 β”‚ 1 β”‚ β”‚ Charles Juarez β”‚ 190000 β”‚ 3 β”‚ 3 β”‚ 2 β”‚ β”‚ Gary Chen β”‚ 195000 β”‚ 4 β”‚ 4 β”‚ 3 β”‚ β”‚ Robert George β”‚ 195000 β”‚ 5 β”‚ 4 β”‚ 3 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Aggregation functions[​](https://clickhouse.com/docs/sql-reference/window-functions#aggregation-functions "Direct link to Aggregation functions") Compare each player's salary to the average for their team. ``` SELECT player, salary, team, avg(salary) OVER (PARTITION BY team) AS teamAvg, salary - teamAvg AS diff FROM salaries; ``` ``` β”Œβ”€player──────────┬─salary─┬─team──────────────────────┬─teamAvg─┬───diff─┐ β”‚ Charles Juarez β”‚ 190000 β”‚ New Coreystad Archdukes β”‚ 170000 β”‚ 20000 β”‚ β”‚ Scott Harrison β”‚ 150000 β”‚ New Coreystad Archdukes β”‚ 170000 β”‚ -20000 β”‚ β”‚ Gary Chen β”‚ 195000 β”‚ Port Elizabeth Barbarians β”‚ 180000 β”‚ 15000 β”‚ β”‚ Michael Stanley β”‚ 150000 β”‚ Port Elizabeth Barbarians β”‚ 180000 β”‚ -30000 β”‚ β”‚ Robert George β”‚ 195000 β”‚ Port Elizabeth Barbarians β”‚ 180000 β”‚ 15000 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` Compare each player's salary to the maximum for their team. ``` SELECT player, salary, team, max(salary) OVER (PARTITION BY team) AS teamMax, salary - teamMax AS diff FROM salaries; ``` ``` β”Œβ”€player──────────┬─salary─┬─team──────────────────────┬─teamMax─┬───diff─┐ β”‚ Charles Juarez β”‚ 190000 β”‚ New Coreystad Archdukes β”‚ 190000 β”‚ 0 β”‚ β”‚ Scott Harrison β”‚ 150000 β”‚ New Coreystad Archdukes β”‚ 190000 β”‚ -40000 β”‚ β”‚ Gary Chen β”‚ 195000 β”‚ Port Elizabeth Barbarians β”‚ 195000 β”‚ 0 β”‚ β”‚ Michael Stanley β”‚ 150000 β”‚ Port Elizabeth Barbarians β”‚ 195000 β”‚ -45000 β”‚ β”‚ Robert George β”‚ 195000 β”‚ Port Elizabeth Barbarians β”‚ 195000 β”‚ 0 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Partitioning by column[​](https://clickhouse.com/docs/sql-reference/window-functions#partitioning-by-column "Direct link to Partitioning by column") ``` CREATE TABLE wf_partition ( `part_key` UInt64, `value` UInt64, `order` UInt64 ) ENGINE = Memory; INSERT INTO wf_partition FORMAT Values (1,1,1), (1,2,2), (1,3,3), (2,0,0), (3,0,0); SELECT part_key, value, order, groupArray(value) OVER (PARTITION BY part_key) AS frame_values FROM wf_partition ORDER BY part_key ASC, value ASC; β”Œβ”€part_key─┬─value─┬─order─┬─frame_values─┐ β”‚ 1 β”‚ 1 β”‚ 1 β”‚ [1,2,3] β”‚ <┐ β”‚ 1 β”‚ 2 β”‚ 2 β”‚ [1,2,3] β”‚ β”‚ 1-st group β”‚ 1 β”‚ 3 β”‚ 3 β”‚ [1,2,3] β”‚ <β”˜ β”‚ 2 β”‚ 0 β”‚ 0 β”‚ [0] β”‚ <- 2-nd group β”‚ 3 β”‚ 0 β”‚ 0 β”‚ [0] β”‚ <- 3-d group β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Frame bounding[​](https://clickhouse.com/docs/sql-reference/window-functions#frame-bounding "Direct link to Frame bounding") ``` CREATE TABLE wf_frame ( `part_key` UInt64, `value` UInt64, `order` UInt64 ) ENGINE = Memory; INSERT INTO wf_frame FORMAT Values (1,1,1), (1,2,2), (1,3,3), (1,4,4), (1,5,5); ``` ``` -- Frame is bounded by bounds of a partition (BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) SELECT part_key, value, order, groupArray(value) OVER ( PARTITION BY part_key ORDER BY order ASC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) AS frame_values FROM wf_frame ORDER BY part_key ASC, value ASC; β”Œβ”€part_key─┬─value─┬─order─┬─frame_values─┐ β”‚ 1 β”‚ 1 β”‚ 1 β”‚ [1,2,3,4,5] β”‚ β”‚ 1 β”‚ 2 β”‚ 2 β”‚ [1,2,3,4,5] β”‚ β”‚ 1 β”‚ 3 β”‚ 3 β”‚ [1,2,3,4,5] β”‚ β”‚ 1 β”‚ 4 β”‚ 4 β”‚ [1,2,3,4,5] β”‚ β”‚ 1 β”‚ 5 β”‚ 5 β”‚ [1,2,3,4,5] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ``` -- short form - no bound expression, no order by, -- an equalent of `ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING` SELECT part_key, value, order, groupArray(value) OVER (PARTITION BY part_key) AS frame_values_short, groupArray(value) OVER (PARTITION BY part_key ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) AS frame_values FROM wf_frame ORDER BY part_key ASC, value ASC; β”Œβ”€part_key─┬─value─┬─order─┬─frame_values_short─┬─frame_values─┐ β”‚ 1 β”‚ 1 β”‚ 1 β”‚ [1,2,3,4,5] β”‚ [1,2,3,4,5] β”‚ β”‚ 1 β”‚ 2 β”‚ 2 β”‚ [1,2,3,4,5] β”‚ [1,2,3,4,5] β”‚ β”‚ 1 β”‚ 3 β”‚ 3 β”‚ [1,2,3,4,5] β”‚ [1,2,3,4,5] β”‚ β”‚ 1 β”‚ 4 β”‚ 4 β”‚ [1,2,3,4,5] β”‚ [1,2,3,4,5] β”‚ β”‚ 1 β”‚ 5 β”‚ 5 β”‚ [1,2,3,4,5] β”‚ [1,2,3,4,5] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ``` -- frame is bounded by the beginning of a partition and the current row SELECT part_key, value, order, groupArray(value) OVER ( PARTITION BY part_key ORDER BY order ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS frame_values FROM wf_frame ORDER BY part_key ASC, value ASC; β”Œβ”€part_key─┬─value─┬─order─┬─frame_values─┐ β”‚ 1 β”‚ 1 β”‚ 1 β”‚ [1] β”‚ β”‚ 1 β”‚ 2 β”‚ 2 β”‚ [1,2] β”‚ β”‚ 1 β”‚ 3 β”‚ 3 β”‚ [1,2,3] β”‚ β”‚ 1 β”‚ 4 β”‚ 4 β”‚ [1,2,3,4] β”‚ β”‚ 1 β”‚ 5 β”‚ 5 β”‚ [1,2,3,4,5] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ``` -- short form (frame is bounded by the beginning of a partition and the current row) -- an equalent of `ORDER BY order ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW` SELECT part_key, value, order, groupArray(value) OVER (PARTITION BY part_key ORDER BY order ASC) AS frame_values_short, groupArray(value) OVER (PARTITION BY part_key ORDER BY order ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS frame_values FROM wf_frame ORDER BY part_key ASC, value ASC; β”Œβ”€part_key─┬─value─┬─order─┬─frame_values_short─┬─frame_values─┐ β”‚ 1 β”‚ 1 β”‚ 1 β”‚ [1] β”‚ [1] β”‚ β”‚ 1 β”‚ 2 β”‚ 2 β”‚ [1,2] β”‚ [1,2] β”‚ β”‚ 1 β”‚ 3 β”‚ 3 β”‚ [1,2,3] β”‚ [1,2,3] β”‚ β”‚ 1 β”‚ 4 β”‚ 4 β”‚ [1,2,3,4] β”‚ [1,2,3,4] β”‚ β”‚ 1 β”‚ 5 β”‚ 5 β”‚ [1,2,3,4,5] β”‚ [1,2,3,4,5] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ``` -- frame is bounded by the beginning of a partition and the current row, but order is backward SELECT part_key, value, order, groupArray(value) OVER (PARTITION BY part_key ORDER BY order DESC) AS frame_values FROM wf_frame ORDER BY part_key ASC, value ASC; β”Œβ”€part_key─┬─value─┬─order─┬─frame_values─┐ β”‚ 1 β”‚ 1 β”‚ 1 β”‚ [5,4,3,2,1] β”‚ β”‚ 1 β”‚ 2 β”‚ 2 β”‚ [5,4,3,2] β”‚ β”‚ 1 β”‚ 3 β”‚ 3 β”‚ [5,4,3] β”‚ β”‚ 1 β”‚ 4 β”‚ 4 β”‚ [5,4] β”‚ β”‚ 1 β”‚ 5 β”‚ 5 β”‚ [5] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ``` -- sliding frame - 1 PRECEDING ROW AND CURRENT ROW SELECT part_key, value, order, groupArray(value) OVER ( PARTITION BY part_key ORDER BY order ASC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW ) AS frame_values FROM wf_frame ORDER BY part_key ASC, value ASC; β”Œβ”€part_key─┬─value─┬─order─┬─frame_values─┐ β”‚ 1 β”‚ 1 β”‚ 1 β”‚ [1] β”‚ β”‚ 1 β”‚ 2 β”‚ 2 β”‚ [1,2] β”‚ β”‚ 1 β”‚ 3 β”‚ 3 β”‚ [2,3] β”‚ β”‚ 1 β”‚ 4 β”‚ 4 β”‚ [3,4] β”‚ β”‚ 1 β”‚ 5 β”‚ 5 β”‚ [4,5] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ``` -- sliding frame - ROWS BETWEEN 1 PRECEDING AND UNBOUNDED FOLLOWING SELECT part_key, value, order, groupArray(value) OVER ( PARTITION BY part_key ORDER BY order ASC ROWS BETWEEN 1 PRECEDING AND UNBOUNDED FOLLOWING ) AS frame_values FROM wf_frame ORDER BY part_key ASC, value ASC; β”Œβ”€part_key─┬─value─┬─order─┬─frame_values─┐ β”‚ 1 β”‚ 1 β”‚ 1 β”‚ [1,2,3,4,5] β”‚ β”‚ 1 β”‚ 2 β”‚ 2 β”‚ [1,2,3,4,5] β”‚ β”‚ 1 β”‚ 3 β”‚ 3 β”‚ [2,3,4,5] β”‚ β”‚ 1 β”‚ 4 β”‚ 4 β”‚ [3,4,5] β”‚ β”‚ 1 β”‚ 5 β”‚ 5 β”‚ [4,5] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ``` -- row_number does not respect the frame, so rn_1 = rn_2 = rn_3 != rn_4 SELECT part_key, value, order, groupArray(value) OVER w1 AS frame_values, row_number() OVER w1 AS rn_1, sum(1) OVER w1 AS rn_2, row_number() OVER w2 AS rn_3, sum(1) OVER w2 AS rn_4 FROM wf_frame WINDOW w1 AS (PARTITION BY part_key ORDER BY order DESC), w2 AS ( PARTITION BY part_key ORDER BY order DESC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW ) ORDER BY part_key ASC, value ASC; β”Œβ”€part_key─┬─value─┬─order─┬─frame_values─┬─rn_1─┬─rn_2─┬─rn_3─┬─rn_4─┐ β”‚ 1 β”‚ 1 β”‚ 1 β”‚ [5,4,3,2,1] β”‚ 5 β”‚ 5 β”‚ 5 β”‚ 2 β”‚ β”‚ 1 β”‚ 2 β”‚ 2 β”‚ [5,4,3,2] β”‚ 4 β”‚ 4 β”‚ 4 β”‚ 2 β”‚ β”‚ 1 β”‚ 3 β”‚ 3 β”‚ [5,4,3] β”‚ 3 β”‚ 3 β”‚ 3 β”‚ 2 β”‚ β”‚ 1 β”‚ 4 β”‚ 4 β”‚ [5,4] β”‚ 2 β”‚ 2 β”‚ 2 β”‚ 2 β”‚ β”‚ 1 β”‚ 5 β”‚ 5 β”‚ [5] β”‚ 1 β”‚ 1 β”‚ 1 β”‚ 1 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”˜ ``` ``` -- first_value and last_value respect the frame SELECT groupArray(value) OVER w1 AS frame_values_1, first_value(value) OVER w1 AS first_value_1, last_value(value) OVER w1 AS last_value_1, groupArray(value) OVER w2 AS frame_values_2, first_value(value) OVER w2 AS first_value_2, last_value(value) OVER w2 AS last_value_2 FROM wf_frame WINDOW w1 AS (PARTITION BY part_key ORDER BY order ASC), w2 AS (PARTITION BY part_key ORDER BY order ASC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) ORDER BY part_key ASC, value ASC; β”Œβ”€frame_values_1─┬─first_value_1─┬─last_value_1─┬─frame_values_2─┬─first_value_2─┬─last_value_2─┐ β”‚ [1] β”‚ 1 β”‚ 1 β”‚ [1] β”‚ 1 β”‚ 1 β”‚ β”‚ [1,2] β”‚ 1 β”‚ 2 β”‚ [1,2] β”‚ 1 β”‚ 2 β”‚ β”‚ [1,2,3] β”‚ 1 β”‚ 3 β”‚ [2,3] β”‚ 2 β”‚ 3 β”‚ β”‚ [1,2,3,4] β”‚ 1 β”‚ 4 β”‚ [3,4] β”‚ 3 β”‚ 4 β”‚ β”‚ [1,2,3,4,5] β”‚ 1 β”‚ 5 β”‚ [4,5] β”‚ 4 β”‚ 5 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ``` -- second value within the frame SELECT groupArray(value) OVER w1 AS frame_values_1, nth_value(value, 2) OVER w1 AS second_value FROM wf_frame WINDOW w1 AS (PARTITION BY part_key ORDER BY order ASC ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) ORDER BY part_key ASC, value ASC; β”Œβ”€frame_values_1─┬─second_value─┐ β”‚ [1] β”‚ 0 β”‚ β”‚ [1,2] β”‚ 2 β”‚ β”‚ [1,2,3] β”‚ 2 β”‚ β”‚ [1,2,3,4] β”‚ 2 β”‚ β”‚ [2,3,4,5] β”‚ 3 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ``` -- second value within the frame + Null for missing values SELECT groupArray(value) OVER w1 AS frame_values_1, nth_value(toNullable(value), 2) OVER w1 AS second_value FROM wf_frame WINDOW w1 AS (PARTITION BY part_key ORDER BY order ASC ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) ORDER BY part_key ASC, value ASC; β”Œβ”€frame_values_1─┬─second_value─┐ β”‚ [1] β”‚ ᴺᡁᴸᴸ β”‚ β”‚ [1,2] β”‚ 2 β”‚ β”‚ [1,2,3] β”‚ 2 β”‚ β”‚ [1,2,3,4] β”‚ 2 β”‚ β”‚ [2,3,4,5] β”‚ 3 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ## Real world examples[​](https://clickhouse.com/docs/sql-reference/window-functions#real-world-examples "Direct link to Real world examples") The following examples solve common real-world problems. ### Maximum/total salary per department[​](https://clickhouse.com/docs/sql-reference/window-functions#maximumtotal-salary-per-department "Direct link to Maximum/total salary per department") ``` CREATE TABLE employees ( `department` String, `employee_name` String, `salary` Float ) ENGINE = Memory; INSERT INTO employees FORMAT Values ('Finance', 'Jonh', 200), ('Finance', 'Joan', 210), ('Finance', 'Jean', 505), ('IT', 'Tim', 200), ('IT', 'Anna', 300), ('IT', 'Elen', 500); ``` ``` SELECT department, employee_name AS emp, salary, max_salary_per_dep, total_salary_per_dep, round((salary / total_salary_per_dep) * 100, 2) AS `share_per_dep(%)` FROM ( SELECT department, employee_name, salary, max(salary) OVER wndw AS max_salary_per_dep, sum(salary) OVER wndw AS total_salary_per_dep FROM employees WINDOW wndw AS ( PARTITION BY department ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) ORDER BY department ASC, employee_name ASC ); β”Œβ”€department─┬─emp──┬─salary─┬─max_salary_per_dep─┬─total_salary_per_dep─┬─share_per_dep(%)─┐ β”‚ Finance β”‚ Jean β”‚ 505 β”‚ 505 β”‚ 915 β”‚ 55.19 β”‚ β”‚ Finance β”‚ Joan β”‚ 210 β”‚ 505 β”‚ 915 β”‚ 22.95 β”‚ β”‚ Finance β”‚ Jonh β”‚ 200 β”‚ 505 β”‚ 915 β”‚ 21.86 β”‚ β”‚ IT β”‚ Anna β”‚ 300 β”‚ 500 β”‚ 1000 β”‚ 30 β”‚ β”‚ IT β”‚ Elen β”‚ 500 β”‚ 500 β”‚ 1000 β”‚ 50 β”‚ β”‚ IT β”‚ Tim β”‚ 200 β”‚ 500 β”‚ 1000 β”‚ 20 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Cumulative sum[​](https://clickhouse.com/docs/sql-reference/window-functions#cumulative-sum "Direct link to Cumulative sum") ``` CREATE TABLE warehouse ( `item` String, `ts` DateTime, `value` Float ) ENGINE = Memory INSERT INTO warehouse VALUES ('sku38', '2020-01-01', 9), ('sku38', '2020-02-01', 1), ('sku38', '2020-03-01', -4), ('sku1', '2020-01-01', 1), ('sku1', '2020-02-01', 1), ('sku1', '2020-03-01', 1); ``` ``` SELECT item, ts, value, sum(value) OVER (PARTITION BY item ORDER BY ts ASC) AS stock_balance FROM warehouse ORDER BY item ASC, ts ASC; β”Œβ”€item──┬──────────────────ts─┬─value─┬─stock_balance─┐ β”‚ sku1 β”‚ 2020-01-01 00:00:00 β”‚ 1 β”‚ 1 β”‚ β”‚ sku1 β”‚ 2020-02-01 00:00:00 β”‚ 1 β”‚ 2 β”‚ β”‚ sku1 β”‚ 2020-03-01 00:00:00 β”‚ 1 β”‚ 3 β”‚ β”‚ sku38 β”‚ 2020-01-01 00:00:00 β”‚ 9 β”‚ 9 β”‚ β”‚ sku38 β”‚ 2020-02-01 00:00:00 β”‚ 1 β”‚ 10 β”‚ β”‚ sku38 β”‚ 2020-03-01 00:00:00 β”‚ -4 β”‚ 6 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Moving / sliding average (per 3 rows)[​](https://clickhouse.com/docs/sql-reference/window-functions#moving--sliding-average-per-3-rows "Direct link to Moving / sliding average (per 3 rows)") ``` CREATE TABLE sensors ( `metric` String, `ts` DateTime, `value` Float ) ENGINE = Memory; insert into sensors values('cpu_temp', '2020-01-01 00:00:00', 87), ('cpu_temp', '2020-01-01 00:00:01', 77), ('cpu_temp', '2020-01-01 00:00:02', 93), ('cpu_temp', '2020-01-01 00:00:03', 87), ('cpu_temp', '2020-01-01 00:00:04', 87), ('cpu_temp', '2020-01-01 00:00:05', 87), ('cpu_temp', '2020-01-01 00:00:06', 87), ('cpu_temp', '2020-01-01 00:00:07', 87); ``` ``` SELECT metric, ts, value, avg(value) OVER ( PARTITION BY metric ORDER BY ts ASC ROWS BETWEEN 2 PRECEDING AND CURRENT ROW ) AS moving_avg_temp FROM sensors ORDER BY metric ASC, ts ASC; β”Œβ”€metric───┬──────────────────ts─┬─value─┬───moving_avg_temp─┐ β”‚ cpu_temp β”‚ 2020-01-01 00:00:00 β”‚ 87 β”‚ 87 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:00:01 β”‚ 77 β”‚ 82 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:00:02 β”‚ 93 β”‚ 85.66666666666667 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:00:03 β”‚ 87 β”‚ 85.66666666666667 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:00:04 β”‚ 87 β”‚ 89 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:00:05 β”‚ 87 β”‚ 87 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:00:06 β”‚ 87 β”‚ 87 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:00:07 β”‚ 87 β”‚ 87 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Moving / sliding average (per 10 seconds)[​](https://clickhouse.com/docs/sql-reference/window-functions#moving--sliding-average-per-10-seconds "Direct link to Moving / sliding average (per 10 seconds)") ``` SELECT metric, ts, value, avg(value) OVER (PARTITION BY metric ORDER BY ts RANGE BETWEEN 10 PRECEDING AND CURRENT ROW) AS moving_avg_10_seconds_temp FROM sensors ORDER BY metric ASC, ts ASC; β”Œβ”€metric───┬──────────────────ts─┬─value─┬─moving_avg_10_seconds_temp─┐ β”‚ cpu_temp β”‚ 2020-01-01 00:00:00 β”‚ 87 β”‚ 87 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:01:10 β”‚ 77 β”‚ 77 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:02:20 β”‚ 93 β”‚ 93 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:03:30 β”‚ 87 β”‚ 87 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:04:40 β”‚ 87 β”‚ 87 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:05:50 β”‚ 87 β”‚ 87 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:06:00 β”‚ 87 β”‚ 87 β”‚ β”‚ cpu_temp β”‚ 2020-01-01 00:07:10 β”‚ 87 β”‚ 87 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Moving / sliding average (per 10 days)[​](https://clickhouse.com/docs/sql-reference/window-functions#moving--sliding-average-per-10-days "Direct link to Moving / sliding average (per 10 days)") Temperature is stored with second precision, but using `Range` and `ORDER BY toDate(ts)` we form a frame with the size of 10 units, and because of `toDate(ts)` the unit is a day. ``` CREATE TABLE sensors ( `metric` String, `ts` DateTime, `value` Float ) ENGINE = Memory; insert into sensors values('ambient_temp', '2020-01-01 00:00:00', 16), ('ambient_temp', '2020-01-01 12:00:00', 16), ('ambient_temp', '2020-01-02 11:00:00', 9), ('ambient_temp', '2020-01-02 12:00:00', 9), ('ambient_temp', '2020-02-01 10:00:00', 10), ('ambient_temp', '2020-02-01 12:00:00', 10), ('ambient_temp', '2020-02-10 12:00:00', 12), ('ambient_temp', '2020-02-10 13:00:00', 12), ('ambient_temp', '2020-02-20 12:00:01', 16), ('ambient_temp', '2020-03-01 12:00:00', 16), ('ambient_temp', '2020-03-01 12:00:00', 16), ('ambient_temp', '2020-03-01 12:00:00', 16); ``` ``` SELECT metric, ts, value, round(avg(value) OVER (PARTITION BY metric ORDER BY toDate(ts) RANGE BETWEEN 10 PRECEDING AND CURRENT ROW),2) AS moving_avg_10_days_temp FROM sensors ORDER BY metric ASC, ts ASC; β”Œβ”€metric───────┬──────────────────ts─┬─value─┬─moving_avg_10_days_temp─┐ β”‚ ambient_temp β”‚ 2020-01-01 00:00:00 β”‚ 16 β”‚ 16 β”‚ β”‚ ambient_temp β”‚ 2020-01-01 12:00:00 β”‚ 16 β”‚ 16 β”‚ β”‚ ambient_temp β”‚ 2020-01-02 11:00:00 β”‚ 9 β”‚ 12.5 β”‚ β”‚ ambient_temp β”‚ 2020-01-02 12:00:00 β”‚ 9 β”‚ 12.5 β”‚ β”‚ ambient_temp β”‚ 2020-02-01 10:00:00 β”‚ 10 β”‚ 10 β”‚ β”‚ ambient_temp β”‚ 2020-02-01 12:00:00 β”‚ 10 β”‚ 10 β”‚ β”‚ ambient_temp β”‚ 2020-02-10 12:00:00 β”‚ 12 β”‚ 11 β”‚ β”‚ ambient_temp β”‚ 2020-02-10 13:00:00 β”‚ 12 β”‚ 11 β”‚ β”‚ ambient_temp β”‚ 2020-02-20 12:00:01 β”‚ 16 β”‚ 13.33 β”‚ β”‚ ambient_temp β”‚ 2020-03-01 12:00:00 β”‚ 16 β”‚ 16 β”‚ β”‚ ambient_temp β”‚ 2020-03-01 12:00:00 β”‚ 16 β”‚ 16 β”‚ β”‚ ambient_temp β”‚ 2020-03-01 12:00:00 β”‚ 16 β”‚ 16 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ## References[​](https://clickhouse.com/docs/sql-reference/window-functions#references "Direct link to References") ### GitHub Issues[​](https://clickhouse.com/docs/sql-reference/window-functions#github-issues "Direct link to GitHub Issues") The roadmap for the initial support of window functions is [in this issue](https://github.com/ClickHouse/ClickHouse/issues/18097). All GitHub issues related to window functions have the [comp-window-functions](https://github.com/ClickHouse/ClickHouse/labels/comp-window-functions) tag. ### Tests[​](https://clickhouse.com/docs/sql-reference/window-functions#tests "Direct link to Tests") These tests contain the examples of the currently supported grammar: <https://github.com/ClickHouse/ClickHouse/blob/master/tests/performance/window_functions.xml> <https://github.com/ClickHouse/ClickHouse/blob/master/tests/queries/0_stateless/01591_window_functions.sql> ### Postgres Docs[​](https://clickhouse.com/docs/sql-reference/window-functions#postgres-docs "Direct link to Postgres Docs") <https://www.postgresql.org/docs/current/sql-select.html#SQL-WINDOW> <https://www.postgresql.org/docs/devel/sql-expressions.html#SYNTAX-WINDOW-FUNCTIONS> <https://www.postgresql.org/docs/devel/functions-window.html> <https://www.postgresql.org/docs/devel/tutorial-window.html> ### MySQL Docs[​](https://clickhouse.com/docs/sql-reference/window-functions#mysql-docs "Direct link to MySQL Docs") <https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html> <https://dev.mysql.com/doc/refman/8.0/en/window-functions-usage.html> <https://dev.mysql.com/doc/refman/8.0/en/window-functions-frames.html> ## Related Content[​](https://clickhouse.com/docs/sql-reference/window-functions#related-content "Direct link to Related Content") - Blog: [Working with time series data in ClickHouse](https://clickhouse.com/blog/working-with-time-series-data-and-functions-ClickHouse) - Blog: [Window and array functions for Git commit sequences](https://clickhouse.com/blog/clickhouse-window-array-functions-git-commits) - Blog: [Getting Data Into ClickHouse - Part 3 - Using S3](https://clickhouse.com/blog/getting-data-into-clickhouse-part-3-s3)
Shard89 (laksa)
Root Hash12633450985039531489
Unparsed URLcom,clickhouse!/docs/sql-reference/window-functions s443