In short and very simplified: window functions retain result row, group by
squashes them. If the information you need relates to aggregation you need group by
, if the information relates to particular row you need window function.
For example: supposed you have collection of employees with department and salaries. To know what is the average salary in department, you use select dept_id, avg(salary) from emp group by dept
(aggregation). To know how each employee differs from that average, use select emp_id, salary - avg(salary) over (partition by dept_id) from emp
(window function).
There are also several use cases which can be solved by both window functions and group by
, for example select grp, min(value) ... group by grp
is equivalent to select grp, value from (select grp, row_number() over (partition by grp order by value) as rn, value ...) x where x.rn = 1
) so the border is somewhat fuzzy and other criteria (such as readability, extensibility or performance) have to help to decide.