There are plenty of posts on web, describing PostgreSQL window functions, and I decided to make another one, to share my
view and my approach to understanding them.

Queries using window functions usually look like this one:

Window function part is starting from avg(salary). The window functions introduce the concepts of window frames
In the above example, avg(salary) is the function, that is being applied to every row in the output.
The frame is representing the relation that is available to avg(salary) on the current row. In the example, the frame is
defined by PARTITION BY depname part. The whole relation available to window function initially, after filtering clauses,
is being partitioned by depname column’s value. It results in

(5200 + 4200 + 4500 + 6000 + 5200)/5 = 5020.0

And we get the value of 5020.0 in every row related to develop depname. The same applies to personnel and sales depnames.

The frame is defined either by partition by or order by clauses, otherwise, the defaults are applied.

when partition by is used - the frame consists of the whole partition

when order by is used - the frame includes all records up to current row. Further records are omitted

Here we see the illustration of frame scoping to all the rows up to the current row. We have ordered the relation by empno
column value. On the first row, avg(salary) takes into account only first row, on the second row - first row + second row, and so on.

when both clauses are omitted, the frame includes the whole relation

avg is now applied to the whole table.

The avg function used in the previous example is an aggregation function.
Window functions can be used with aggregate functions, or with so-called built-in window functions.
List of built-in window functions can be viewed here

Another thing to note is that window functions are evaluated after filtering and grouping clauses, therefore we cannot
use grouping and filtering over windowing results.