Window Functions in SQL: What They Are and How to Use Them

Introduction

Window functions in SQL let you do calculations across rows related to the current row, without combining them into one. Unlike regular aggregate functions, window functions keep each row in the result; they just look at other rows while calculating.

For example, you can calculate:

  • the rank of each salesperson within their region,
  • a running total of sales for each customer,
  • or the difference between current and previous month’s revenue.
SELECT
  [Customer No_],
  [Location Code],
  [Remaining Amount],
  SUM([Remaining Amount]) OVER (
    PARTITION BY [Location Code]
    ORDER BY [Customer No_]
  ) AS LocationOutstandingTotal
FROM [Customer Ledger Entry];
  • We’re calculating the sum of [Remaining Amount]
  • OVER (...) turns it into a window function
  • PARTITION BY [Location Code] groups the rows by location
  • ORDER BY [Customer No_] gives a running total within each location

Note: You can’t use window functions directly in a GROUP BY clause or mix them with group-based aggregations.

References

https://www.postgresql.org/docs/9.1/tutorial-window.html
Mode - Window Functions

Usage/Examples

The SUM() window function adds up values over a defined set of rows related to the current row.
The AVG() window function gives the average value over the window of rows.
The COUNT() window function counts how many rows are in the window frame for each row.

By adding "ORDER BY" inside the window function tells SQL to process rows in a specific order (by start_time) within each start_terminal group.
This converts it into a running total/average/count.

ROW_NUMBER() - Assigns a unique row number to each row, starting from 1 in each partition.
RANK() - Ranks rows within a partition, but skips ranks if there are ties (e.g. 1, 2, 2, 4).
DENSE_RANK() - It is similar to RANK(), but does not skip numbers (1, 2, 2, 3).

The below screenshot with row number 12 highlights the difference between rank and denserank.

LAG() - Returns the value of a column from a previous row in the partition.
LEAD() - Returns the value of a column from a next row in the partition.
FIRST_VALUE() - Returns the first or last value within the window frame.
LAST_VALUE() - Returns the last value within the window frame.

Note that I did not add an "Order By" on the Last_Value function as that would've ended up showing me the current value (as it works like a running total with Order By) and skipping "Order By" gave me the absolute last value within the frame.

Using a WINDOW Alias

If you are using the same window (PARTITION BY / ORDER BY) in several window functions, you don’t need to repeat it each time.
You can define it once using a WINDOW clause and then use an alias.

This makes the query neat and tidy while also reducing redundancy.

Note: The WINDOW clause (if used) should come after the WHERE clause in your query.

Conclusion

Window functions help you do more with your SQL queries. You can calculate running totals, ranks, averages, and compare rows without losing the details of each row.

They can save you from writing long and complicated queries. Once you get used to using simple window functions like SUM() or ROW_NUMBER(), you can explore more like LAG() or RANK().

Try using them in your reports, you’ll find that your queries become easier to write and understand.

Comments

Popular posts from this blog

Event-Driven Architecture: How to Create Custom Business Events in Business Central

Leverage Postman for Streamlined API Testing in Finance and Operations

Integration with Finance and Operations - From Basics (Part 2)