Lesson Description
Use analytical SQL to rank, compare, and calculate trends across partitions without losing row-level detail.
Lesson 4 of 4
Progress: 0/3 exercises solved (0%)
Solve all exercises below to unlock the next lesson.
Lesson Description
Use analytical SQL to rank, compare, and calculate trends across partitions without losing row-level detail.
Easy Project
Mini project: Build a compensation ranking dashboard query with department-level rank and delta from the top earner.
By default, aggregate window functions accumulate from the start of the partition to the current row. A frame clause lets you control exactly which rows are included.
function() OVER (
PARTITION BY col
ORDER BY col
ROWS BETWEEN <start> AND <end>
)
| Keyword | Meaning |
|---|---|
UNBOUNDED PRECEDING | First row of partition |
n PRECEDING | n rows before current row |
CURRENT ROW | The current row |
n FOLLOWING | n rows after current row |
UNBOUNDED FOLLOWING | Last row of partition |
SELECT
hire_date, salary,
SUM(salary) OVER (
ORDER BY hire_date, id
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS running_total
FROM employees
ORDER BY hire_date, id;
This is the default frame when ORDER BY is present — writing it explicitly is optional but clarifies intent.
SELECT
hire_date, salary,
ROUND(AVG(salary) OVER (
ORDER BY hire_date, id
ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
), 2) AS moving_avg_3
FROM employees
ORDER BY hire_date, id;
SELECT
department_id, salary,
ROUND(
salary / SUM(salary) OVER (
PARTITION BY department_id
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) * 100, 2
) AS pct_of_dept
FROM employees
ORDER BY department_id, salary DESC;
| OVER() content | Default frame |
|---|---|
| No ORDER BY | Entire partition |
| Has ORDER BY | UNBOUNDED PRECEDING TO CURRENT ROW |
RANGE BETWEEN instead of ROWS BETWEEN when you want to include all rows with the same ORDER BY value as the current row.ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING gives the full-partition total on every row — useful for percentage calculations.This lesson is part of Window Functions. Focus on the core idea in Window frames — ROWS BETWEEN, then validate with deliberate practice.
What to master
Common mistakes
High-level strategy
Task ladder
Transparent data checks
Retention loop
Logical reasoning for commands
WHERE
Why: Limits rows to only the business-relevant subset.
Memory cue: Filter early to reduce noise.
ORDER BY
Why: Makes output deterministic and reviewable.
Memory cue: No ORDER BY means no guaranteed row order.
AS alias
Why: Makes output columns readable for teams and reports.
Memory cue: If the name is clear, the query is easier to trust.
Concept check
3 quick questions. One at a time. Instant score at the end.
Return first_name, last_name, hire_date, salary, and running_total — a cumulative sum of salary ordered by hire_date, then id. Use ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW.
Return first_name, last_name, hire_date, salary, and moving_avg — the average salary across the current employee and 1 row before and 1 row after (ordered by hire_date, id). Round to 2 decimal places.
Return first_name, last_name, department_id, salary, and pct_of_dept — each employee's salary as a percentage of their department's total salary. Use ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING. Round to 2 decimal places. Order by department_id, salary descending.
Final checkpoint
Pass mark: 80%. Review each explanation after you submit.
1. Which clause should you use to filter grouped results?
2. What is the safest way to avoid accidental row multiplication in joins?
3. Which feature is best for ranking rows within partitions?
4. Why should final analytical queries usually include ORDER BY?
5. When query logic gets complex, what improves readability most?
Lesson 4 of 4
0/3 solved (0%)
Finish this lesson to unlock next.