select number, count() over (partition by intDiv(number, 3) order by number rows unbounded preceding) from numbers(10);
0 1
1 2
2 3
3 1
4 2
5 3
6 1
7 2
8 3
9 1
-- proper calculation across blocks
select number, max(number) over (partition by intDiv(number, 3) order by number desc rows unbounded preceding) from numbers(10) settings max_block_size = 2;
2 2
1 2
0 2
5 5
4 5
3 5
8 8
7 8
6 8
9 9
-- not a window function
select number, abs(number) over (partition by toString(intDiv(number, 3)) rows unbounded preceding) from numbers(10); -- { serverError 63 }
-- no partition by
select number, avg(number) over (order by number rows unbounded preceding) from numbers(10);
-- can't reference it yet -- the window functions are calculated at the
-- last stage of select, after all other functions.
select q * 10, quantileExact(number) over (partition by intDiv(number, 3) rows unbounded preceding) q from numbers(10); -- { serverError 47 }
-- must work in WHERE if you wrap it in a subquery
select * from (select count(*) over (rows unbounded preceding) c from numbers(3)) where c > 0;
1
2
3
-- should work in ORDER BY
select number, max(number) over (partition by intDiv(number, 3) order by number desc rows unbounded preceding) m from numbers(10) order by m desc, number;
9 9
6 8
7 8
8 8
3 5
4 5
5 5
0 2
1 2
2 2
-- also works in ORDER BY if you wrap it in a subquery
select * from (select count(*) over (rows unbounded preceding) c from numbers(3)) order by c;
1
2
3
-- Example with window function only in ORDER BY. Here we make a rank of all
-- numbers sorted descending, and then sort by this rank descending, and must get
-- the ascending order.
select * from (select * from numbers(5) order by rand()) order by count() over (order by number desc rows unbounded preceding) desc;
0
1
2
3
4
-- Aggregate functions as window function arguments. This query is semantically
-- the same as the above one, only we replace `number` with
-- `any(number) group by number` and so on.
select * from (select * from numbers(5) order by rand()) group by number order by sum(any(number + 1)) over (order by min(number) desc rows unbounded preceding) desc;
0
1
2
3
4
-- some more simple cases w/aggregate functions
select sum(any(number)) over (rows unbounded preceding) from numbers(1);
0
select sum(any(number) + 1) over (rows unbounded preceding) from numbers(1);
1
select sum(any(number + 1)) over (rows unbounded preceding) from numbers(1);
1
-- different windows
-- an explain test would also be helpful, but it's too immature now and I don't
-- want to change reference all the time
select number, max(number) over (partition by intDiv(number, 3) order by number desc rows unbounded preceding), count(number) over (partition by intDiv(number, 5) order by number rows unbounded preceding) as m from numbers(31) order by number settings max_block_size = 2;
0 2 1
1 2 2
2 2 3
3 5 4
4 5 5
5 5 1
6 8 2
7 8 3
8 8 4
9 11 5
10 11 1
11 11 2
12 14 3
13 14 4
14 14 5
15 17 1
16 17 2
17 17 3
18 20 4
19 20 5
20 20 1
21 23 2
22 23 3
23 23 4
24 26 5
25 26 1
26 26 2
27 29 3
28 29 4
29 29 5
30 30 1
-- two functions over the same window
-- an explain test would also be helpful, but it's too immature now and I don't
-- want to change reference all the time
select number, max(number) over (partition by intDiv(number, 3) order by number desc rows unbounded preceding), count(number) over (partition by intDiv(number, 3) order by number desc rows unbounded preceding) as m from numbers(7) order by number settings max_block_size = 2;
0 2 3
1 2 2
2 2 1
3 5 3
4 5 2
5 5 1
6 6 1
-- check that we can work with constant columns
select median(x) over (partition by x) from (select 1 x);
1
-- an empty window definition is valid as well
select groupArray(number) over (rows unbounded preceding) from numbers(3);
[0]
[0,1]
[0,1,2]
select groupArray(number) over () from numbers(3);
[0,1,2]
[0,1,2]
[0,1,2]
-- This one tests we properly process the window function arguments.
-- Seen errors like 'column `1` not found' from count(1).
select count(1) over (rows unbounded preceding), max(number + 1) over () from numbers(3);
1 3
2 3
3 3
-- Should work in DISTINCT
select distinct sum(0) over (rows unbounded preceding) from numbers(2);
0
select distinct any(number) over (rows unbounded preceding) from numbers(2);
0
-- Various kinds of aliases are properly substituted into various parts of window
-- function definition.
with number + 1 as x select intDiv(number, 3) as y, sum(x + y) over (partition by y order by x rows unbounded preceding) from numbers(7);
select number, intDiv(number, 2) p, mod(number, 3) o, count(number) over w as c
from numbers(31)
window w as (partition by p order by o range unbounded preceding)
order by number
settings max_block_size = 5
;
0 0 0 1
1 0 1 2
2 1 2 2
3 1 0 1
4 2 1 1
5 2 2 2
6 3 0 1
7 3 1 2
8 4 2 2
9 4 0 1
10 5 1 1
11 5 2 2
12 6 0 1
13 6 1 2
14 7 2 2
15 7 0 1
16 8 1 1
17 8 2 2
18 9 0 1
19 9 1 2
20 10 2 2
21 10 0 1
22 11 1 1
23 11 2 2
24 12 0 1
25 12 1 2
26 13 2 2
27 13 0 1
28 14 1 1
29 14 2 2
30 15 0 1
-- A case where the partition end is in the current block, and the frame end
-- is triggered by the partition end.
select min(number) over (partition by p) from (select number, intDiv(number, 3) p from numbers(10));
0
0
0
3
3
3
6
6
6
9
-- UNBOUNDED FOLLOWING frame end
select
min(number) over wa, min(number) over wo,
max(number) over wa, max(number) over wo
from
(select number, intDiv(number, 3) p, mod(number, 5) o
from numbers(31))
window
wa as (partition by p order by o
range between unbounded preceding and unbounded following),
wo as (partition by p order by o
rows between unbounded preceding and unbounded following)
settings max_block_size = 2;
0 0 2 2
0 0 2 2
0 0 2 2
3 3 5 5
3 3 5 5
3 3 5 5
6 6 8 8
6 6 8 8
6 6 8 8
9 9 11 11
9 9 11 11
9 9 11 11
12 12 14 14
12 12 14 14
12 12 14 14
15 15 17 17
15 15 17 17
15 15 17 17
18 18 20 20
18 18 20 20
18 18 20 20
21 21 23 23
21 21 23 23
21 21 23 23
24 24 26 26
24 24 26 26
24 24 26 26
27 27 29 29
27 27 29 29
27 27 29 29
30 30 30 30
-- ROWS offset frame start
select number, p,
count(*) over (partition by p order by number
rows between 1 preceding and unbounded following),
count(*) over (partition by p order by number
rows between current row and unbounded following),
count(*) over (partition by p order by number
rows between 1 following and unbounded following)
from (select number, intDiv(number, 5) p from numbers(31))
order by p, number
settings max_block_size = 2;
0 0 5 5 4
1 0 5 4 3
2 0 4 3 2
3 0 3 2 1
4 0 2 1 0
5 1 5 5 4
6 1 5 4 3
7 1 4 3 2
8 1 3 2 1
9 1 2 1 0
10 2 5 5 4
11 2 5 4 3
12 2 4 3 2
13 2 3 2 1
14 2 2 1 0
15 3 5 5 4
16 3 5 4 3
17 3 4 3 2
18 3 3 2 1
19 3 2 1 0
20 4 5 5 4
21 4 5 4 3
22 4 4 3 2
23 4 3 2 1
24 4 2 1 0
25 5 5 5 4
26 5 5 4 3
27 5 4 3 2
28 5 3 2 1
29 5 2 1 0
30 6 1 1 0
-- ROWS offset frame start and end
select number, p,
count(*) over (partition by p order by number
rows between 2 preceding and 2 following)
from (select number, intDiv(number, 7) p from numbers(71))
order by p, number
settings max_block_size = 2;
0 0 3
1 0 4
2 0 5
3 0 5
4 0 5
5 0 4
6 0 3
7 1 3
8 1 4
9 1 5
10 1 5
11 1 5
12 1 4
13 1 3
14 2 3
15 2 4
16 2 5
17 2 5
18 2 5
19 2 4
20 2 3
21 3 3
22 3 4
23 3 5
24 3 5
25 3 5
26 3 4
27 3 3
28 4 3
29 4 4
30 4 5
31 4 5
32 4 5
33 4 4
34 4 3
35 5 3
36 5 4
37 5 5
38 5 5
39 5 5
40 5 4
41 5 3
42 6 3
43 6 4
44 6 5
45 6 5
46 6 5
47 6 4
48 6 3
49 7 3
50 7 4
51 7 5
52 7 5
53 7 5
54 7 4
55 7 3
56 8 3
57 8 4
58 8 5
59 8 5
60 8 5
61 8 4
62 8 3
63 9 3
64 9 4
65 9 5
66 9 5
67 9 5
68 9 4
69 9 3
70 10 1
SELECT count(*) OVER (ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) FROM numbers(4);
1
2
3
3
-- frame boundaries that runs into the partition end
select
count() over (partition by intDiv(number, 3)
rows between 100 following and unbounded following),
count() over (partition by intDiv(number, 3)
rows between current row and 100 following)
from numbers(10);
0 3
0 2
0 1
0 3
0 2
0 1
0 3
0 2
0 1
0 1
-- seen a use-after-free under MSan in this query once
SELECT number, max(number) OVER (PARTITION BY intDiv(number, 7) ORDER BY number ASC NULLS LAST ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) FROM numbers(1024) SETTINGS max_block_size = 2 FORMAT Null;
-- a corner case
select count() over ();
1
-- RANGE CURRENT ROW frame start
select number, p, o,
count(*) over (partition by p order by o
range between current row and unbounded following)
from (select number, intDiv(number, 5) p, mod(number, 3) o
from numbers(31))
order by p, o, number
settings max_block_size = 2;
0 0 0 5
3 0 0 5
1 0 1 3
4 0 1 3
2 0 2 1
6 1 0 5
9 1 0 5
7 1 1 3
5 1 2 2
8 1 2 2
12 2 0 5
10 2 1 4
13 2 1 4
11 2 2 2
14 2 2 2
15 3 0 5
18 3 0 5
16 3 1 3
19 3 1 3
17 3 2 1
21 4 0 5
24 4 0 5
22 4 1 3
20 4 2 2
23 4 2 2
27 5 0 5
25 5 1 4
28 5 1 4
26 5 2 2
29 5 2 2
30 6 0 1
select
count(*) over (rows between current row and current row),
count(*) over (range between current row and current row)
from numbers(3);
1 3
1 3
1 3
-- RANGE OFFSET
-- a basic RANGE OFFSET frame
select x, min(x) over w, max(x) over w, count(x) over w from (
select toUInt8(number) x from numbers(11))
window w as (order by x asc range between 1 preceding and 2 following)
order by x;
0 0 2 3
1 0 3 4
2 1 4 4
3 2 5 4
4 3 6 4
5 4 7 4
6 5 8 4
7 6 9 4
8 7 10 4
9 8 10 3
10 9 10 2
-- overflow conditions
select x, min(x) over w, max(x) over w, count(x) over w
from (
select toUInt8(if(mod(number, 2),
toInt64(255 - intDiv(number, 2)),
toInt64(intDiv(number, 2)))) x
from numbers(10)
)
window w as (order by x range between 1 preceding and 2 following)
order by x;
0 0 2 3
1 0 3 4
2 1 4 4
3 2 4 3
4 3 4 2
251 251 253 3
252 251 254 4
253 252 255 4
254 253 255 3
255 254 255 2
select x, min(x) over w, max(x) over w, count(x) over w
select count() over (w partition by number) from numbers(1) window w as (partition by intDiv(number, 5)); -- { serverError 36 }
-- can't redefine existing ORDER BY
select count() over (w order by number) from numbers(1) window w as (partition by intDiv(number, 5) order by mod(number, 3)); -- { serverError 36 }
-- parent window can't have frame
select count() over (w range unbounded preceding) from numbers(1) window w as (partition by intDiv(number, 5) order by mod(number, 3) rows unbounded preceding); -- { serverError 36 }
-- looks weird but probably should work -- this is a window that inherits and changes nothing
select count() over (w) from numbers(1) window w as ();