Simple Window Function
October 8, 2012
Here's a simple window function, used to work out a count of rows.
bands_band
rows have a link to a regions_region
row.
These two queries produce the same results. First, a simple count
:
SELECT r.name, count(b.region_id) FROM regions_region r INNER JOIN bands_band b ON (r.id = b.region_id) GROUP BY r.name ORDER BY 2 desc
Next, an equivalent query using a window function:
SELECT DISTINCT ON (r.name) r.name, count(b.region_id) over (PARTITION BY b.region_id) FROM regions_region r INNER JOIN bands_band b ON b.region_id = r.id
If we want to order this query, we can use a subquery like this:
SELECT * FROM (SELECT DISTINCT ON (r.name) r.name, count(b.region_id) over (PARTITION BY b.region_id) FROM regions_region r INNER JOIN bands_band b ON b.region_id = r.id) x ORDER BY 2 desc
So what's the point of the window function?
Using window functions it's possible to aggregate over different things in different parts of the query. GROUP BY
would refer to the entire query, here we can create a "window" specific to a given result column.
We can use it to produce a list of bands along with the number of bands that are also in that region:
SELECT b.name, count(*) over (PARTITION BY b.region_id) FROM bands_band b
We can also easily expand this to include the region name:
SELECT b.name, r.name, count(*) over (PARTITION BY b.region_id) FROM bands_band b INNER JOIN regions_region r on (r.id = b.region_id)
Bands have a description of the national_grading level on them, held in b.national_grading
. We can add this column to the results, along with a count
of other bands with the same grading:
SELECT b.name, r.name, count(*) over (PARTITION BY b.region_id) as region_count, b.national_grading, count(*) over (PARTITION by b.national_grading) as grading_count FROM bands_band b INNER JOIN regions_region r on (r.id = b.region_id)