Skip to main content

Window Functions

Window functions perform calculations across a set of rows that are related to the current row. Unlike aggregate functions with GROUP BY, window functions do not collapse rows into a single output row. Every input row produces a corresponding output row, with the window function result appended.
Turso supports aggregate functions used as window functions with the default frame definition. Custom frame specifications (ROWS, RANGE, or GROUPS with explicit bounds) and dedicated window functions (row_number, rank, dense_rank, ntile, lag, lead, first_value, last_value, nth_value) are not yet supported.

Syntax

aggregate_function(expression) OVER (
    [PARTITION BY expression [, ...]]
    [ORDER BY expression [ASC | DESC] [, ...]]
)
ClauseDescription
aggregate_functionAny supported aggregate function: count, sum, avg, min, max, total, group_concat
OVER (...)Defines the window over which the function operates
PARTITION BYDivides the result set into partitions. The function is applied independently within each partition. If omitted, the entire result set is one partition
ORDER BYDefines the order of rows within each partition. This determines which rows are included in the frame for each calculation

Default Frame

When ORDER BY is specified, the default frame is:
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
This means the function considers all rows from the start of the partition up to and including the current row (and any rows with equal ORDER BY values, since the frame mode is RANGE). When ORDER BY is omitted, the default frame covers the entire partition.

Supported Aggregate Functions as Window Functions

Any aggregate function can be used as a window function by adding an OVER clause.
FunctionDescription
count(*)Number of rows in the frame
count(expression)Number of non-NULL values in the frame
sum(expression)Sum of non-NULL values in the frame
avg(expression)Average of non-NULL values in the frame
min(expression)Minimum value in the frame
max(expression)Maximum value in the frame
total(expression)Sum as REAL (returns 0.0 for empty frames instead of NULL)
group_concat(expression, separator)Concatenation of values in the frame

PARTITION BY

PARTITION BY divides the rows into groups. The window function resets and recalculates independently for each partition.
SELECT
    department,
    name,
    salary,
    SUM(salary) OVER (PARTITION BY department) AS dept_total
FROM employees;
departmentnamesalarydept_total
EngineeringAlice90000250000
EngineeringBob85000250000
EngineeringCarol75000250000
MarketingDave70000130000
MarketingEve60000130000
Without PARTITION BY, the function treats the entire result set as one partition:
SELECT
    name,
    salary,
    SUM(salary) OVER () AS company_total
FROM employees;

ORDER BY

ORDER BY within the OVER clause determines row ordering within each partition. Combined with the default frame (RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW), this produces running calculations.
SELECT
    name,
    salary,
    SUM(salary) OVER (ORDER BY salary) AS running_total
FROM employees;
namesalaryrunning_total
Eve6000060000
Dave70000130000
Carol75000205000
Bob85000290000
Alice90000380000

PARTITION BY with ORDER BY

Use both clauses together for running calculations within groups:
SELECT
    department,
    name,
    salary,
    SUM(salary) OVER (
        PARTITION BY department
        ORDER BY salary
    ) AS dept_running_total
FROM employees;
departmentnamesalarydept_running_total
EngineeringCarol7500075000
EngineeringBob85000160000
EngineeringAlice90000250000
MarketingEve6000060000
MarketingDave70000130000

Named Windows

The WINDOW clause defines a reusable window specification that can be referenced by multiple window functions in the same query. This avoids repeating the same OVER definition.
SELECT
    department,
    name,
    salary,
    SUM(salary) OVER w AS running_total,
    AVG(salary) OVER w AS running_avg,
    COUNT(*) OVER w AS running_count
FROM employees
WINDOW w AS (PARTITION BY department ORDER BY salary)
ORDER BY department, salary;
Multiple named windows can be defined:
SELECT
    department,
    name,
    salary,
    SUM(salary) OVER dept AS dept_total,
    SUM(salary) OVER company AS company_total
FROM employees
WINDOW
    dept AS (PARTITION BY department),
    company AS ()
ORDER BY department, name;

Examples

Running Total

SELECT
    order_date,
    amount,
    SUM(amount) OVER (ORDER BY order_date) AS running_total
FROM orders;

Count per Group

-- Show each employee alongside their department headcount
SELECT
    name,
    department,
    COUNT(*) OVER (PARTITION BY department) AS dept_size
FROM employees
ORDER BY department, name;

Running Average

SELECT
    date,
    temperature,
    AVG(temperature) OVER (ORDER BY date) AS running_avg_temp
FROM weather_readings
ORDER BY date;

Percentage of Total

SELECT
    product_name,
    revenue,
    ROUND(100.0 * revenue / SUM(revenue) OVER (), 2) AS pct_of_total
FROM products
ORDER BY revenue DESC;

Multiple Window Functions in One Query

SELECT
    department,
    name,
    salary,
    MIN(salary) OVER (PARTITION BY department) AS dept_min,
    MAX(salary) OVER (PARTITION BY department) AS dept_max,
    AVG(salary) OVER (PARTITION BY department) AS dept_avg,
    salary - AVG(salary) OVER (PARTITION BY department) AS diff_from_avg
FROM employees
ORDER BY department, salary DESC;

Group Concatenation over a Window

SELECT
    department,
    name,
    GROUP_CONCAT(name, ', ') OVER (PARTITION BY department ORDER BY name) AS names_so_far
FROM employees;

Limitations

The following window function features are not yet supported in Turso:
FeatureStatus
row_number()Not supported
rank()Not supported
dense_rank()Not supported
ntile(N)Not supported
lag(expr, offset, default)Not supported
lead(expr, offset, default)Not supported
first_value(expr)Not supported
last_value(expr)Not supported
nth_value(expr, N)Not supported
cume_dist()Not supported
percent_rank()Not supported
Custom frame: ROWS BETWEEN ...Not supported
Custom frame: RANGE BETWEEN ... AND ...Not supported
Custom frame: GROUPS BETWEEN ...Not supported
EXCLUDE clauseNot supported
FILTER (WHERE ...) on window functionsNot supported

See Also