DBMSCSL303 / MAL505
Module 3: Advanced SQL & Analytics

Lecture 09b: Window Functions & Analytical SQL

OVER Clause, PARTITION BY, Ranking Functions (ROW_NUMBER, RANK, DENSE_RANK), Window Frames, and Offset Functions (LEAD, LAG)

Lecture Source Slide Deck

Original Slides: Lecture 09b (37 slides) · Amit Kumar Dhar (IIT Bhilai)
Download lecture09b.pdf

1. The Big Idea: Window Functions vs. Aggregation

FeatureStandard GROUP BY AggregationAnalytical Window Function
Row CountCollapses multiple rows into a single summary row per group.Preserves every individual row in the final output.
Output AccessCan only output grouped or aggregated expressions.Can display both granular row details AND aggregate benchmarks side-by-side.
SyntaxGROUP BY columnOVER (PARTITION BY ... ORDER BY ...)
-- Compare each instructor's salary against their department's average
SELECT 
    name,
    dept_name,
    salary,
    ROUND(AVG(salary) OVER (PARTITION BY dept_name), 2) AS dept_avg,
    salary - ROUND(AVG(salary) OVER (PARTITION BY dept_name), 2) AS diff_from_avg
FROM instructor;

2. Anatomy of the OVER Clause

FUNCTION() OVER (
    [PARTITION BY partition_column, ...]
    [ORDER BY sort_column [ASC|DESC], ...]
    [ROWS BETWEEN frame_start AND frame_end]
)
  1. PARTITION BY: Divides the dataset into distinct subsets (windows). If omitted, the entire table is treated as one giant window.
  2. ORDER BY: Dictates the logical sequence in which window calculations (running sums, ranks) process rows inside the partition.
  3. ROWS BETWEEN: Defines the physical frame of rows evaluated for the current row.

3. Ranking Functions Compared

Suppose three instructors have salaries: [90000, 90000, 75000].

NameSalaryROW_NUMBER()RANK()DENSE_RANK()
Alice90,000111
Bob90,000211
Charlie75,00033 (skips 2)2 (never skips)
  • ROW_NUMBER(): Generates a strict strictly increasing sequence 1, 2, 3, ... with no ties.
  • RANK(): Assigns duplicate ranks on ties, and leaves gaps in the subsequent numbers.
  • DENSE_RANK(): Assigns duplicate ranks on ties, but guarantees contiguous numbering without gaps.

4. The Canonical "Top-N Per Group" Problem

To find the top 2 highest-paid instructors in each department:

WITH RankedFaculty AS (
    SELECT 
        name,
        dept_name,
        salary,
        DENSE_RANK() OVER (
            PARTITION BY dept_name 
            ORDER BY salary DESC
        ) AS rank_in_dept
    FROM instructor
)
SELECT name, dept_name, salary, rank_in_dept
FROM RankedFaculty
WHERE rank_in_dept <= 2;

Rule: Window functions cannot be filtered directly in a WHERE clause because WHERE runs before window functions. A CTE or subquery is required.


5. Running Totals & Window Frames

-- Compute cumulative running total of department salary spend
SELECT 
    dept_name,
    name,
    salary,
    SUM(salary) OVER (
        PARTITION BY dept_name 
        ORDER BY salary DESC
        ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
    ) AS running_total
FROM instructor;

Frame Boundaries:

  • UNBOUNDED PRECEDING: The very first row of the partition.
  • n PRECEDING: n rows prior to the current row.
  • CURRENT ROW: The row currently being calculated.
  • n FOLLOWING: n rows after the current row.
  • UNBOUNDED FOLLOWING: The final row of the partition.

6. Offset Navigation Functions: LAG and LEAD

  • LAG(col, n): Accesses the value of col from n rows before the current row.
  • LEAD(col, n): Accesses the value of col from n rows after the current row.
-- Calculate student tot_cred progress relative to the student ranked immediately below
SELECT 
    name,
    tot_cred,
    LAG(tot_cred, 1) OVER (ORDER BY tot_cred DESC) AS higher_peer_cred,
    tot_cred - LAG(tot_cred, 1) OVER (ORDER BY tot_cred DESC) AS difference
FROM student;

7. Topic Practice Questions

On this page