Bird
Raised Fist0
PostgreSQLquery~10 mins

Practical window function patterns in PostgreSQL - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Practical window function patterns
Start with table data
↓
Define window function
↓
Partition data (optional)
↓
Order data within partition
↓
Calculate window function value
↓
Return rows with window values
↓
End
Window functions process rows with optional partitioning and ordering, returning values alongside original rows.
Execution Sample
PostgreSQL
SELECT emp_id, dept, salary,
       RANK() OVER (PARTITION BY dept ORDER BY salary DESC) AS rank
FROM employees;
Ranks employees by salary within each department.
Execution Table
Stepemp_iddeptsalaryPartition (dept)Order in PartitionRANK() Result
1101Sales7000Sales11
2102Sales6000Sales22
3103Sales6000Sales32
4104HR8000HR11
5105HR7500HR22
6106HR7000HR33
7107IT9000IT11
8108IT8500IT22
ExitAll rows processed, ranks assigned
💡 All rows processed, ranks assigned
Variable Tracker
VariableStartAfter 1After 2After 3After 4After 5After 6After 7After 8Final
emp_id101102103104105106107108
deptSalesSalesSalesHRHRHRITIT
salary70006000600080007500700090008500
RANK()12212312
Key Moments - 3 Insights
Why do employees with the same salary get the same rank?
Because RANK() assigns the same rank to ties, as shown in rows 2 and 3 where salary 6000 gets rank 2 for both.
What happens when the partition changes?
The ranking restarts at 1 for each new department partition, as seen when moving from Sales to HR at row 4.
Why is ordering important inside the partition?
Ordering determines the rank order; without ORDER BY salary DESC, ranks would not reflect salary order.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution table, what is the rank of emp_id 105 at step 5?
A3
B1
C2
D4
💡 Hint
Check the RANK() Result column at step 5 for emp_id 105.
At which step does the partition change from Sales to HR?
AStep 4
BStep 5
CStep 3
DStep 6
💡 Hint
Look at the Partition (dept) column to see when it changes.
If we remove ORDER BY salary DESC, what would happen to the ranks?
ARanks would all be 1
BRanks would be assigned randomly within partitions
CRanks would be assigned in insertion order
DRanks would be NULL
💡 Hint
Ordering defines how ranks are assigned; without it, order is not guaranteed.
Concept Snapshot
Window functions compute values across rows related to the current row.
Syntax: function() OVER (PARTITION BY col ORDER BY col)
Partition divides data groups; order defines sequence.
Common functions: RANK(), ROW_NUMBER(), SUM(), AVG().
Results appear alongside original rows without grouping.
Full Transcript
This lesson shows how window functions work in PostgreSQL. We start with a table of employees with departments and salaries. The RANK() function assigns ranks to employees within each department based on salary order. The process partitions data by department, orders salaries descending, then calculates ranks. Equal salaries get the same rank, and ranks restart for each department. The execution table traces each row's rank assignment step-by-step. Key points include understanding partition changes, tie handling, and the importance of ordering. The quiz tests understanding of ranks at specific steps, partition changes, and effects of removing ordering. Window functions let you analyze data across rows without losing row details.

Practice

(1/5)
1. What does the ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) window function do in a query?
easy
A. Counts the number of employees in each department.
B. Assigns a unique rank to each employee within their department based on salary, starting at 1 for the highest salary.
C. Calculates the total salary for each department.
D. Returns the average salary of all employees.

Solution

  1. Step 1: Understand ROW_NUMBER() with PARTITION BY

    The function assigns a unique sequential number to rows within each department group.
  2. Step 2: ORDER BY salary DESC ranks highest salary first

    Ordering by salary descending means the highest salary gets row number 1 in each department.
  3. Final Answer:

    Assigns a unique rank to each employee within their department based on salary, starting at 1 for the highest salary. -> Option B
  4. Quick Check:

    ROW_NUMBER() with PARTITION BY and ORDER BY = ranked rows [OK]
Hint: ROW_NUMBER() numbers rows per group ordered by criteria [OK]
Common Mistakes:
  • Confusing ROW_NUMBER() with COUNT() or SUM()
  • Ignoring PARTITION BY and thinking it ranks globally
  • Assuming it calculates totals or averages
2. Which of the following is the correct syntax to calculate a running total of sales ordered by date using window functions in PostgreSQL?
easy
A. SELECT date, sales, SUM(sales) PARTITION BY date FROM sales_data;
B. SELECT date, sales, SUM(sales) GROUP BY date ORDER BY running_total FROM sales_data;
C. SELECT date, sales, SUM(sales) WHERE ORDER BY date FROM sales_data;
D. SELECT date, sales, SUM(sales) OVER (ORDER BY date) AS running_total FROM sales_data;

Solution

  1. Step 1: Identify correct window function syntax

    SUM(sales) OVER (ORDER BY date) calculates running total by ordering rows by date.
  2. Step 2: Check other options for syntax errors

    The incorrect options misuse PARTITION BY without OVER(), use WHERE incorrectly, or confuse GROUP BY with window functions.
  3. Final Answer:

    SELECT date, sales, SUM(sales) OVER (ORDER BY date) AS running_total FROM sales_data; -> Option D
  4. Quick Check:

    SUM() OVER (ORDER BY ...) = running total syntax [OK]
Hint: Use OVER() with ORDER BY for running totals [OK]
Common Mistakes:
  • Using PARTITION BY without OVER()
  • Trying to use WHERE inside window function
  • Confusing GROUP BY with window functions
3. Given the table sales(date, amount) with rows:
('2024-01-01', 100), ('2024-01-02', 150), ('2024-01-03', 200)
What is the output of this query?
SELECT date, amount, SUM(amount) OVER (ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS running_total FROM sales ORDER BY date;
medium
A. [('2024-01-01', 100, 450), ('2024-01-02', 150, 350), ('2024-01-03', 200, 200)]
B. [('2024-01-01', 100, 100), ('2024-01-02', 150, 150), ('2024-01-03', 200, 200)]
C. [('2024-01-01', 100, 100), ('2024-01-02', 150, 250), ('2024-01-03', 200, 450)]
D. [('2024-01-01', 100, NULL), ('2024-01-02', 150, NULL), ('2024-01-03', 200, NULL)]

Solution

  1. Step 1: Understand SUM() OVER with frame

    The frame includes all rows from the start up to current row ordered by date, so it sums cumulatively.
  2. Step 2: Calculate running totals row by row

    Row 1: 100; Row 2: 100+150=250; Row 3: 250+200=450.
  3. Final Answer:

    [('2024-01-01', 100, 100), ('2024-01-02', 150, 250), ('2024-01-03', 200, 450)] -> Option C
  4. Quick Check:

    Running total sums up to current row [OK]
Hint: ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW sums cumulatively [OK]
Common Mistakes:
  • Ignoring frame clause and expecting total sum on all rows
  • Confusing running total with simple SUM() aggregation
  • Assuming NULLs appear without reason
4. You wrote this query to rank employees by salary within each department:
SELECT employee_id, department, salary, RANK() OVER (ORDER BY salary DESC) AS dept_rank FROM employees;

But the query returns the same rank for all employees regardless of department. What is the likely mistake?
medium
A. Missing PARTITION BY clause inside OVER()
B. ORDER BY salary ASC instead of DESC
C. Using RANK() instead of ROW_NUMBER()
D. Not ordering the final result by department

Solution

  1. Step 1: Check PARTITION BY usage

    If PARTITION BY is missing or incorrect, ranking happens over entire table, ignoring departments.
  2. Step 2: Confirm ORDER BY and function choice

    ORDER BY DESC is correct for highest salary first; RANK() is appropriate for ties; ordering final result doesn't affect ranking.
  3. Final Answer:

    Missing PARTITION BY clause inside OVER() -> Option A
  4. Quick Check:

    PARTITION BY groups rows for ranking [OK]
Hint: Always include PARTITION BY to rank within groups [OK]
Common Mistakes:
  • Forgetting PARTITION BY causes global ranking
  • Confusing RANK() and ROW_NUMBER() effects
  • Thinking ORDER BY outside OVER() affects ranking
5. You want to find each employee's salary difference compared to the previous employee in the same department ordered by salary descending. Which query correctly uses window functions to achieve this?
hard
A. SELECT employee_id, department, salary, salary - LAG(salary) OVER (PARTITION BY department ORDER BY salary DESC) AS salary_diff FROM employees;
B. SELECT employee_id, department, salary, salary - LEAD(salary) OVER (ORDER BY salary) AS salary_diff FROM employees;
C. SELECT employee_id, department, salary, salary - LAG(salary) FROM employees GROUP BY department ORDER BY salary DESC;
D. SELECT employee_id, department, salary, salary - FIRST_VALUE(salary) OVER (PARTITION BY department) AS salary_diff FROM employees;

Solution

  1. Step 1: Use LAG() to get previous row's salary per department

    LAG(salary) OVER (PARTITION BY department ORDER BY salary DESC) gets previous salary in descending order within department.
  2. Step 2: Subtract previous salary from current salary

    salary - LAG(salary) calculates difference compared to previous employee.
  3. Final Answer:

    SELECT employee_id, department, salary, salary - LAG(salary) OVER (PARTITION BY department ORDER BY salary DESC) AS salary_diff FROM employees; -> Option A
  4. Quick Check:

    LAG() gets previous row value for difference [OK]
Hint: Use LAG() with PARTITION BY and ORDER BY for previous row values [OK]
Common Mistakes:
  • Using LEAD() instead of LAG() for previous row
  • Omitting PARTITION BY causing wrong grouping
  • Trying to use aggregate functions without OVER()
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard