From 2697a3932186258eaca1744de3ae9af5dace0a28 Mon Sep 17 00:00:00 2001 From: Dmitriy Pavlov Date: Tue, 14 Jul 2026 20:47:41 +0300 Subject: [PATCH 1/3] IGNITE-28895 Document Calcite window functions --- docs/_docs/SQL/sql-calcite.adoc | 55 +++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/docs/_docs/SQL/sql-calcite.adoc b/docs/_docs/SQL/sql-calcite.adoc index d60a732cd66bc..bca52008b403a 100644 --- a/docs/_docs/SQL/sql-calcite.adoc +++ b/docs/_docs/SQL/sql-calcite.adoc @@ -274,6 +274,61 @@ The Calcite-based SQL engine currently supports the following user-facing functi |=== +==== Window functions + +Calcite-based SQL engine supports window functions with the `OVER` clause. Window definitions can use +`PARTITION BY`, `ORDER BY`, and `ROWS` or `RANGE` frame clauses. + +[source,sql] +---- +SELECT depname, empno, salary, + RANK() OVER (PARTITION BY depname ORDER BY salary) AS salary_rank, + SUM(salary) OVER (PARTITION BY depname) AS dep_salary +FROM empsalary; +---- + +[cols="1,2,4",opts="stretch,header"] +|=== +|Name | Syntax | Description + +|Aggregate window function +|`aggregateFunction(...) OVER windowSpecification` +|Evaluates an aggregate function over the rows in the current window. + +|`ROW_NUMBER` +|`ROW_NUMBER() OVER windowSpecification` +|Returns the ordinal number of the current row within the window. + +|`RANK` +|`RANK() OVER windowSpecification` +|Returns the rank of the current row within the window, with gaps after peer rows. + +|`DENSE_RANK` +|`DENSE_RANK() OVER windowSpecification` +|Returns the rank of the current row within the window, without gaps after peer rows. + +|`PERCENT_RANK` +|`PERCENT_RANK() OVER windowSpecification` +|Returns the relative rank of the current row within the window. + +|`CUME_DIST` +|`CUME_DIST() OVER windowSpecification` +|Returns the cumulative distribution of the current row within the window. + +|`LAG` +|`LAG(value[, offset[, default]]) OVER windowSpecification` +|Returns a value from a preceding row in the window, or the default value when that row does not exist. + +|`LEAD` +|`LEAD(value[, offset[, default]]) OVER windowSpecification` +|Returns a value from a following row in the window, or the default value when that row does not exist. + +|`FIRST_VALUE` +|`FIRST_VALUE(value) OVER windowSpecification` +|Returns the first value in the window frame. + +|=== + ==== String functions and predicates [cols="1,2,4",opts="stretch,header"] From 0f6d52174bbc59b54c4b2be4447939da779e1512 Mon Sep 17 00:00:00 2001 From: Dmitriy Pavlov Date: Tue, 14 Jul 2026 21:27:23 +0300 Subject: [PATCH 2/3] IGNITE-28895 Detail Calcite window frame syntax --- docs/_docs/SQL/sql-calcite.adoc | 92 ++++++++++++++++++++------------- 1 file changed, 57 insertions(+), 35 deletions(-) diff --git a/docs/_docs/SQL/sql-calcite.adoc b/docs/_docs/SQL/sql-calcite.adoc index bca52008b403a..ace12c2052175 100644 --- a/docs/_docs/SQL/sql-calcite.adoc +++ b/docs/_docs/SQL/sql-calcite.adoc @@ -276,59 +276,81 @@ The Calcite-based SQL engine currently supports the following user-facing functi ==== Window functions -Calcite-based SQL engine supports window functions with the `OVER` clause. Window definitions can use -`PARTITION BY`, `ORDER BY`, and `ROWS` or `RANGE` frame clauses. +Calcite-based SQL engine supports window functions with the `OVER` clause. A window function can use an inline window specification: [source,sql] ---- -SELECT depname, empno, salary, - RANK() OVER (PARTITION BY depname ORDER BY salary) AS salary_rank, - SUM(salary) OVER (PARTITION BY depname) AS dep_salary -FROM empsalary; +windowFunction(...) OVER ( + [PARTITION BY expression[, expression]...] + [ORDER BY expression [ASC | DESC] [NULLS FIRST | NULLS LAST][, expression ...]] + [{ROWS | RANGE} frameExtent] +) ---- -[cols="1,2,4",opts="stretch,header"] +The window specification defines which rows are visible to the function for the current row. + +[cols="1,3",opts="stretch,header"] |=== -|Name | Syntax | Description +|Clause | Description -|Aggregate window function -|`aggregateFunction(...) OVER windowSpecification` -|Evaluates an aggregate function over the rows in the current window. +|`PARTITION BY` +|Splits the input rows into independent partitions. The window function is evaluated within the current row's partition. -|`ROW_NUMBER` -|`ROW_NUMBER() OVER windowSpecification` -|Returns the ordinal number of the current row within the window. +|`ORDER BY` +|Defines row ordering inside each partition. Ranking functions and bounded frames use this ordering. -|`RANK` -|`RANK() OVER windowSpecification` -|Returns the rank of the current row within the window, with gaps after peer rows. +|`ROWS BETWEEN frameStart AND frameEnd` +|Defines a frame by physical row offsets from the current row. -|`DENSE_RANK` -|`DENSE_RANK() OVER windowSpecification` -|Returns the rank of the current row within the window, without gaps after peer rows. +|`RANGE BETWEEN frameStart AND frameEnd` +|Defines a frame by the ordered value range around the current row. -|`PERCENT_RANK` -|`PERCENT_RANK() OVER windowSpecification` -|Returns the relative rank of the current row within the window. +|`UNBOUNDED PRECEDING` +|Starts the frame at the first row of the partition. -|`CUME_DIST` -|`CUME_DIST() OVER windowSpecification` -|Returns the cumulative distribution of the current row within the window. +|`offset PRECEDING` +|Starts or ends the frame before the current row. The offset can be numeric, or an interval for date/time `RANGE` frames. -|`LAG` -|`LAG(value[, offset[, default]]) OVER windowSpecification` -|Returns a value from a preceding row in the window, or the default value when that row does not exist. +|`CURRENT ROW` +|Starts or ends the frame at the current row. -|`LEAD` -|`LEAD(value[, offset[, default]]) OVER windowSpecification` -|Returns a value from a following row in the window, or the default value when that row does not exist. +|`offset FOLLOWING` +|Starts or ends the frame after the current row. The offset can be numeric, or an interval for date/time `RANGE` frames. -|`FIRST_VALUE` -|`FIRST_VALUE(value) OVER windowSpecification` -|Returns the first value in the window frame. +|`UNBOUNDED FOLLOWING` +|Ends the frame at the last row of the partition. |=== +Examples: + +[source,sql] +---- +SELECT depname, empno, salary, + RANK() OVER (PARTITION BY depname ORDER BY salary) AS salary_rank, + SUM(salary) OVER (PARTITION BY depname) AS dep_salary +FROM empsalary; + +SELECT depname, + COUNT(*) OVER ( + PARTITION BY depname + ORDER BY empno + ROWS BETWEEN 2 PRECEDING AND 1 FOLLOWING + ) AS nearby_rows +FROM empsalary; + +SELECT depname, + COUNT(*) OVER ( + PARTITION BY depname + ORDER BY enroll_date + RANGE BETWEEN INTERVAL 730 DAYS PRECEDING AND INTERVAL 360 DAYS FOLLOWING + ) AS nearby_dates +FROM empsalary; +---- + +Window functions can be used with aggregate functions and with ranking/value functions such as `ROW_NUMBER`, `RANK`, +`DENSE_RANK`, `PERCENT_RANK`, `CUME_DIST`, `LAG`, `LEAD`, and `FIRST_VALUE`. + ==== String functions and predicates [cols="1,2,4",opts="stretch,header"] From ad4b6f885a848dd7d405c87101760e22e2cdbeb3 Mon Sep 17 00:00:00 2001 From: Dmitriy Pavlov Date: Tue, 14 Jul 2026 21:43:23 +0300 Subject: [PATCH 3/3] IGNITE-28895 Add SQL window functions reference --- docs/_data/toc.yaml | 2 + docs/_docs/SQL/sql-calcite.adoc | 75 +------- .../_docs/sql-reference/window-functions.adoc | 163 ++++++++++++++++++ 3 files changed, 166 insertions(+), 74 deletions(-) create mode 100644 docs/_docs/sql-reference/window-functions.adoc diff --git a/docs/_data/toc.yaml b/docs/_data/toc.yaml index e8a6eefc570b6..4e93d550796c4 100644 --- a/docs/_data/toc.yaml +++ b/docs/_data/toc.yaml @@ -240,6 +240,8 @@ url: sql-reference/operational-commands - title: Aggregate functions url: sql-reference/aggregate-functions + - title: Window Functions + url: sql-reference/window-functions - title: Numeric Functions url: sql-reference/numeric-functions - title: String Functions diff --git a/docs/_docs/SQL/sql-calcite.adoc b/docs/_docs/SQL/sql-calcite.adoc index ace12c2052175..a2eef96aa0758 100644 --- a/docs/_docs/SQL/sql-calcite.adoc +++ b/docs/_docs/SQL/sql-calcite.adoc @@ -276,80 +276,7 @@ The Calcite-based SQL engine currently supports the following user-facing functi ==== Window functions -Calcite-based SQL engine supports window functions with the `OVER` clause. A window function can use an inline window specification: - -[source,sql] ----- -windowFunction(...) OVER ( - [PARTITION BY expression[, expression]...] - [ORDER BY expression [ASC | DESC] [NULLS FIRST | NULLS LAST][, expression ...]] - [{ROWS | RANGE} frameExtent] -) ----- - -The window specification defines which rows are visible to the function for the current row. - -[cols="1,3",opts="stretch,header"] -|=== -|Clause | Description - -|`PARTITION BY` -|Splits the input rows into independent partitions. The window function is evaluated within the current row's partition. - -|`ORDER BY` -|Defines row ordering inside each partition. Ranking functions and bounded frames use this ordering. - -|`ROWS BETWEEN frameStart AND frameEnd` -|Defines a frame by physical row offsets from the current row. - -|`RANGE BETWEEN frameStart AND frameEnd` -|Defines a frame by the ordered value range around the current row. - -|`UNBOUNDED PRECEDING` -|Starts the frame at the first row of the partition. - -|`offset PRECEDING` -|Starts or ends the frame before the current row. The offset can be numeric, or an interval for date/time `RANGE` frames. - -|`CURRENT ROW` -|Starts or ends the frame at the current row. - -|`offset FOLLOWING` -|Starts or ends the frame after the current row. The offset can be numeric, or an interval for date/time `RANGE` frames. - -|`UNBOUNDED FOLLOWING` -|Ends the frame at the last row of the partition. - -|=== - -Examples: - -[source,sql] ----- -SELECT depname, empno, salary, - RANK() OVER (PARTITION BY depname ORDER BY salary) AS salary_rank, - SUM(salary) OVER (PARTITION BY depname) AS dep_salary -FROM empsalary; - -SELECT depname, - COUNT(*) OVER ( - PARTITION BY depname - ORDER BY empno - ROWS BETWEEN 2 PRECEDING AND 1 FOLLOWING - ) AS nearby_rows -FROM empsalary; - -SELECT depname, - COUNT(*) OVER ( - PARTITION BY depname - ORDER BY enroll_date - RANGE BETWEEN INTERVAL 730 DAYS PRECEDING AND INTERVAL 360 DAYS FOLLOWING - ) AS nearby_dates -FROM empsalary; ----- - -Window functions can be used with aggregate functions and with ranking/value functions such as `ROW_NUMBER`, `RANK`, -`DENSE_RANK`, `PERCENT_RANK`, `CUME_DIST`, `LAG`, `LEAD`, and `FIRST_VALUE`. +The Calcite-based SQL engine supports SQL window functions. See link:sql-reference/window-functions[Window Functions, window=_blank] for syntax, supported functions, and examples. ==== String functions and predicates diff --git a/docs/_docs/sql-reference/window-functions.adoc b/docs/_docs/sql-reference/window-functions.adoc new file mode 100644 index 0000000000000..0853bf25bdd36 --- /dev/null +++ b/docs/_docs/sql-reference/window-functions.adoc @@ -0,0 +1,163 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. += Window Functions + +Window functions calculate a value for each row returned by a query. The value is calculated over a set of rows related +to the current row. This set of rows is called a window. + +A window function is identified by the `OVER` clause. The `OVER` clause defines how rows are partitioned, ordered, and +framed for the function. Unlike regular aggregate functions, aggregate window functions do not collapse rows into a +single grouped result. + +[NOTE] +==== +Window functions are supported by the Calcite-based SQL engine. +==== + +== Supported Window Functions + +Ignite supports aggregate, ranking, and value functions with the `OVER` clause. + +[cols="1,3",opts="stretch,header"] +|=== +|Type |Functions + +|Aggregate +|`AVG`, `COUNT`, `MAX`, `MIN`, `SUM` + +|Ranking +|`CUME_DIST`, `DENSE_RANK`, `NTILE`, `PERCENT_RANK`, `RANK`, `ROW_NUMBER` + +|Value +|`FIRST_VALUE`, `LAG`, `LAST_VALUE`, `LEAD`, `NTH_VALUE` + +|=== + +== Syntax + +[source,sql] +---- +windowFunction([expression[, expression]...]) OVER ( + [PARTITION BY expression[, expression]...] + [ORDER BY expression [ASC | DESC] [NULLS FIRST | NULLS LAST][, expression ...]] + [{ROWS | RANGE} frameExtent] +) +---- + +The frame extent can use one of the following forms: + +[source,sql] +---- +frameStart +BETWEEN frameStart AND frameEnd +---- + +`frameStart` and `frameEnd` can use the following boundaries: + +[source,sql] +---- +UNBOUNDED PRECEDING +offset PRECEDING +CURRENT ROW +offset FOLLOWING +UNBOUNDED FOLLOWING +---- + +== Arguments + +[cols="1,3",opts="stretch,header"] +|=== +|Clause |Description + +|`OVER` +|Defines the window specification for the function. A query can use multiple window functions with the same or different +window specifications. + +|`PARTITION BY` +|Splits the query result into independent partitions. The window function is evaluated within the current row's +partition. If this clause is omitted, the window function uses the whole query result as one partition. + +|`ORDER BY` +|Defines row ordering inside each partition. This ordering belongs to the window specification and is independent from +the query-level `ORDER BY` clause. Ranking functions and bounded frames use this ordering. + +|`ROWS` +|Defines a frame by physical row offsets from the current row. + +|`RANGE` +|Defines a frame by the ordered value range around the current row. Numeric offsets are supported for numeric ordering +expressions. Interval offsets are supported for date and time ordering expressions. + +|`UNBOUNDED PRECEDING` +|Starts the frame at the first row of the partition. + +|`offset PRECEDING` +|Starts or ends the frame before the current row. + +|`CURRENT ROW` +|Starts or ends the frame at the current row. + +|`offset FOLLOWING` +|Starts or ends the frame after the current row. + +|`UNBOUNDED FOLLOWING` +|Ends the frame at the last row of the partition. + +|=== + +== Examples + +The following query calculates a rank and a department salary total for each employee row: + +[source,sql] +---- +SELECT depname, empno, salary, + RANK() OVER (PARTITION BY depname ORDER BY salary) AS salary_rank, + SUM(salary) OVER (PARTITION BY depname) AS dep_salary +FROM empsalary; +---- + +The following query counts rows in a physical frame around the current row: + +[source,sql] +---- +SELECT depname, + COUNT(*) OVER ( + PARTITION BY depname + ORDER BY empno + ROWS BETWEEN 2 PRECEDING AND 1 FOLLOWING + ) AS nearby_rows +FROM empsalary; +---- + +The following query counts rows in a date range around the current row: + +[source,sql] +---- +SELECT depname, + COUNT(*) OVER ( + PARTITION BY depname + ORDER BY enroll_date + RANGE BETWEEN INTERVAL 730 DAYS PRECEDING AND INTERVAL 360 DAYS FOLLOWING + ) AS nearby_dates +FROM empsalary; +---- + +== Usage Notes + +Window functions are evaluated after the `WHERE`, `GROUP BY`, and `HAVING` clauses. They can be used in the `SELECT` +list and in the query-level `ORDER BY` clause. + +Aggregate functions become aggregate window functions when used with the `OVER` clause.