2 3.5. Window Functions #
4 A window function performs a calculation across a set of table rows
5 that are somehow related to the current row. This is comparable to the
6 type of calculation that can be done with an aggregate function.
7 However, window functions do not cause rows to become grouped into a
8 single output row like non-window aggregate calls would. Instead, the
9 rows retain their separate identities. Behind the scenes, the window
10 function is able to access more than just the current row of the query
13 Here is an example that shows how to compare each employee's salary
14 with the average salary in his or her department:
15 SELECT depname, empno, salary, avg(salary) OVER (PARTITION BY depname) FROM emps
18 depname | empno | salary | avg
19 -----------+-------+--------+-----------------------
20 develop | 11 | 5200 | 5020.0000000000000000
21 develop | 7 | 4200 | 5020.0000000000000000
22 develop | 9 | 4500 | 5020.0000000000000000
23 develop | 8 | 6000 | 5020.0000000000000000
24 develop | 10 | 5200 | 5020.0000000000000000
25 personnel | 5 | 3500 | 3700.0000000000000000
26 personnel | 2 | 3900 | 3700.0000000000000000
27 sales | 3 | 4800 | 4866.6666666666666667
28 sales | 1 | 5000 | 4866.6666666666666667
29 sales | 4 | 4800 | 4866.6666666666666667
32 The first three output columns come directly from the table empsalary,
33 and there is one output row for each row in the table. The fourth
34 column represents an average taken across all the table rows that have
35 the same depname value as the current row. (This actually is the same
36 function as the non-window avg aggregate, but the OVER clause causes it
37 to be treated as a window function and computed across the window
40 A window function call always contains an OVER clause directly
41 following the window function's name and argument(s). This is what
42 syntactically distinguishes it from a normal function or non-window
43 aggregate. The OVER clause determines exactly how the rows of the query
44 are split up for processing by the window function. The PARTITION BY
45 clause within OVER divides the rows into groups, or partitions, that
46 share the same values of the PARTITION BY expression(s). For each row,
47 the window function is computed across the rows that fall into the same
48 partition as the current row.
50 You can also control the order in which rows are processed by window
51 functions using ORDER BY within OVER. (The window ORDER BY does not
52 even have to match the order in which the rows are output.) Here is an
54 SELECT depname, empno, salary,
55 row_number() OVER (PARTITION BY depname ORDER BY salary DESC)
58 depname | empno | salary | row_number
59 -----------+-------+--------+------------
60 develop | 8 | 6000 | 1
61 develop | 10 | 5200 | 2
62 develop | 11 | 5200 | 3
63 develop | 9 | 4500 | 4
64 develop | 7 | 4200 | 5
65 personnel | 2 | 3900 | 1
66 personnel | 5 | 3500 | 2
72 As shown here, the row_number window function assigns sequential
73 numbers to the rows within each partition, in the order defined by the
74 ORDER BY clause (with tied rows numbered in an unspecified order).
75 row_number needs no explicit parameter, because its behavior is
76 entirely determined by the OVER clause.
78 The rows considered by a window function are those of the “virtual
79 table” produced by the query's FROM clause as filtered by its WHERE,
80 GROUP BY, and HAVING clauses if any. For example, a row removed because
81 it does not meet the WHERE condition is not seen by any window
82 function. A query can contain multiple window functions that slice up
83 the data in different ways using different OVER clauses, but they all
84 act on the same collection of rows defined by this virtual table.
86 We already saw that ORDER BY can be omitted if the ordering of rows is
87 not important. It is also possible to omit PARTITION BY, in which case
88 there is a single partition containing all rows.
90 There is another important concept associated with window functions:
91 for each row, there is a set of rows within its partition called its
92 window frame. Some window functions act only on the rows of the window
93 frame, rather than of the whole partition. By default, if ORDER BY is
94 supplied then the frame consists of all rows from the start of the
95 partition up through the current row, plus any following rows that are
96 equal to the current row according to the ORDER BY clause. When ORDER
97 BY is omitted the default frame consists of all rows in the partition.
98 ^[5] Here is an example using sum:
99 SELECT salary, sum(salary) OVER () FROM empsalary;
115 Above, since there is no ORDER BY in the OVER clause, the window frame
116 is the same as the partition, which for lack of PARTITION BY is the
117 whole table; in other words each sum is taken over the whole table and
118 so we get the same result for each output row. But if we add an ORDER
119 BY clause, we get very different results:
120 SELECT salary, sum(salary) OVER (ORDER BY salary) FROM empsalary;
136 Here the sum is taken from the first (lowest) salary up through the
137 current one, including any duplicates of the current one (notice the
138 results for the duplicated salaries).
140 Window functions are permitted only in the SELECT list and the ORDER BY
141 clause of the query. They are forbidden elsewhere, such as in GROUP BY,
142 HAVING and WHERE clauses. This is because they logically execute after
143 the processing of those clauses. Also, window functions execute after
144 non-window aggregate functions. This means it is valid to include an
145 aggregate function call in the arguments of a window function, but not
148 If there is a need to filter or group rows after the window
149 calculations are performed, you can use a sub-select. For example:
150 SELECT depname, empno, salary, enroll_date
152 (SELECT depname, empno, salary, enroll_date,
153 row_number() OVER (PARTITION BY depname ORDER BY salary DESC, empno) AS pos
158 The above query only shows the rows from the inner query having
159 row_number less than 3 (that is, the first two rows for each
162 When a query involves multiple window functions, it is possible to
163 write out each one with a separate OVER clause, but this is duplicative
164 and error-prone if the same windowing behavior is wanted for several
165 functions. Instead, each windowing behavior can be named in a WINDOW
166 clause and then referenced in OVER. For example:
167 SELECT sum(salary) OVER w, avg(salary) OVER w
169 WINDOW w AS (PARTITION BY depname ORDER BY salary DESC);
171 More details about window functions can be found in Section 4.2.8,
172 Section 9.22, Section 7.2.5, and the SELECT reference page.
174 ^[5] There are options to define the window frame in other ways, but
175 this tutorial does not cover them. See Section 4.2.8 for details.