Aggregating Windows
All aggregate functions can be used as window functions instead.
All you have to do is add a window with an OVER
clause.
This causes the aggregate function to behave differently than when you use it with GROUP BY
.
Review
Let's review a query we saw when we learned about GROUP BY
.
SELECT
company,
max(salary) AS top_salary
FROM employees
GROUP BY company;
company VARCHAR | top_salary INTEGER |
---|---|
Footbook | 254000 |
Wamazon | 277000 |
Poogle | 300000 |
Remember that GROUP BY
takes a column(s),
looks at the values in each row for that column(s),
and groups together the rows where that value is equal.
This column(s), is pictured in green.
The rest of the columns from that table, pictured in red, have their values globbed into collections. These cannot be selected directly. Aggregate functions are used here to convert these collections into single values, once per row. You are already acquainted with this usage.
New Usage
When aggregate functions are used with windows, there is no grouping happening on the table you are selecting from, i.e. the input table. Instead, the aggregate function aggregates the window. As with other window functions, it runs once per row and generates 1 value per row of the input table.
Here is an example.
SELECT
max(salary) OVER (PARTITION BY company) AS company_max,
*
FROM employees;
company_max INTEGER | id INTEGER | name VARCHAR | company VARCHAR | department VARCHAR | job_title VARCHAR | salary INTEGER | start_date DATE |
---|---|---|---|---|---|---|---|
254000 | 38 | Ronald Graham | Footbook | Integration | Human Markets Orchestrator | 254000 | 2014-08-13 |
254000 | 37 | Gina DuBuque | Footbook | Integration | Dynamic Paradigm Liaison | 95000 | 2017-02-23 |
254000 | 36 | Whitney Goyette | Footbook | Integration | Corporate Program Analyst | 176000 | 2016-12-10 |
254000 | 35 | Laura Raynor | Footbook | Integration | Central Usability Technician | 144000 | 2019-05-19 |
254000 | 34 | Rex Treutel | Footbook | Integration | Human Division Representative | 117000 | 2012-08-04 |
254000 | 33 | Santiago Lockman | Footbook | Solutions | Direct Branding Developer | 195000 | 2013-12-15 |
254000 | 32 | Wilson Maggio | Footbook | Solutions | Principal Intranet Architect | 254000 | 2011-05-12 |
254000 | 31 | Frankie Glover | Footbook | Solutions | Dynamic Solutions Assistant | 42000 | 2015-07-18 |
254000 | 30 | Mrs. Carmen Blick | Footbook | Research | Customer Tactics Consultant | 183000 | 2011-07-23 |
254000 | 29 | Sean Wintheiser II | Footbook | Research | Legacy Configuration Director | 226000 | 2017-08-24 |
254000 | 28 | Toni Fahey | Footbook | Research | National Branding Director | 22000 | 2017-12-06 |
254000 | 27 | Mathew Harber | Footbook | Research | Investor Brand Associate | 149000 | 2017-02-13 |
300000 | 13 | Alberto Monahan | Poogle | Marketing | Central Response Director | 162000 | 2017-02-10 |
300000 | 1 | Claude Barton | Poogle | Functionality | Legacy Paradigm Executive | 245000 | 2013-09-30 |
300000 | 2 | Christy McLaughlin | Poogle | Functionality | Direct Web Coordinator | 55000 | 2017-04-18 |
300000 | 3 | Tami Glover | Poogle | Functionality | Principal Marketing Architect | 262000 | 2017-10-12 |
300000 | 4 | Ana Koepp | Poogle | Infrastructure | Global Factors Assistant | 194000 | 2011-09-27 |
300000 | 5 | Mae Leannon | Poogle | Infrastructure | Principal Usability Agent | 139000 | 2018-01-08 |
300000 | 6 | Norma Krajcik | Poogle | Infrastructure | Global Quality Analyst | 214000 | 2010-01-16 |
300000 | 7 | Cameron Jacobson | Poogle | Infrastructure | Internal Mobility Orchestrator | 299000 | 2016-07-14 |
300000 | 8 | Ruby Connelly | Poogle | Infrastructure | Corporate Division Liaison | 136000 | 2013-08-19 |
300000 | 9 | Antonio Treutel | Poogle | Infrastructure | Investor Quality Assistant | 20000 | 2016-08-31 |
300000 | 10 | Marianne Schamberger | Poogle | Marketing | Future Infrastructure Assistant | 300000 | 2017-03-27 |
300000 | 11 | Shirley Prohaska | Poogle | Marketing | Future Configuration Supervisor | 105000 | 2010-10-11 |
300000 | 12 | Jan Wiza | Poogle | Marketing | Investor Factors Engineer | 293000 | 2018-09-20 |
277000 | 26 | Dana Ernser | Wamazon | Quality | Chief Program Producer | 93000 | 2012-10-22 |
277000 | 25 | Ramon Rohan | Wamazon | Quality | International Applications Consultant | 60000 | 2010-11-07 |
277000 | 24 | Ollie Murphy | Wamazon | Quality | Dynamic Program Director | 277000 | 2018-08-02 |
277000 | 23 | Rosemary Hilll | Wamazon | Quality | Lead Markets Director | 157000 | 2014-09-25 |
277000 | 22 | Jessie Hodkiewicz | Wamazon | Solutions | Future Assurance Producer | 167000 | 2019-03-24 |
277000 | 21 | Sheri Labadie | Wamazon | Solutions | Dynamic Quality Planner | 27000 | 2016-06-13 |
277000 | 20 | Essie Legros | Wamazon | Solutions | Regional Metrics Analyst | 243000 | 2011-02-20 |
277000 | 19 | Candice Konopelski | Wamazon | Marketing | Human Usability Orchestrator | 151000 | 2015-03-19 |
277000 | 18 | Michele Larson | Wamazon | Marketing | Central Group Manager | 151000 | 2016-07-07 |
277000 | 17 | Eula Price | Wamazon | Marketing | Chief Identity Developer | 186000 | 2018-11-09 |
277000 | 16 | Billie Vandervort | Wamazon | Marketing | Senior Data Developer | 118000 | 2010-01-03 |
277000 | 15 | Erik Vandervort | Wamazon | Marketing | Forward Applications Analyst | 136000 | 2017-02-14 |
277000 | 14 | Alberto Dicki | Wamazon | Marketing | Central Division Technician | 131000 | 2018-09-26 |
ORDER BY
is not necessary in this window becausemax()
is not sensitive to ordering. Actually, we have to omit it because it would change the frame, which we'll discuss a bit later.
The key difference here is that whereas GROUP BY
aggregates individual employees into groups,
aggregating on windows preserves the individual employee rows, and each row "sees" the result of max(salary)
.
Every employee row can access the max salary of their respective company. This gives us yet another way to solve the problem of getting the top earner's name at each company.
WITH max_salaries AS (
SELECT
max(salary) OVER (PARTITION BY company) AS company_max,
*
FROM employees
)
SELECT *
FROM max_salaries
WHERE company_max = salary;
company_max INTEGER | id INTEGER | name VARCHAR | company VARCHAR | department VARCHAR | job_title VARCHAR | salary INTEGER | start_date DATE |
---|---|---|---|---|---|---|---|
254000 | 38 | Ronald Graham | Footbook | Integration | Human Markets Orchestrator | 254000 | 2014-08-13 |
254000 | 32 | Wilson Maggio | Footbook | Solutions | Principal Intranet Architect | 254000 | 2011-05-12 |
300000 | 10 | Marianne Schamberger | Poogle | Marketing | Future Infrastructure Assistant | 300000 | 2017-03-27 |
277000 | 24 | Ollie Murphy | Wamazon | Quality | Dynamic Program Director | 277000 | 2018-08-02 |