Free tutorials & notes in Hindi & English · Clean code examples · Mobile friendly learning
MySQL + SQL · Lesson 80

Window Functions in MySQL

Window Functions Keep Detail Rows

A window function calculates over rows related to the current row but does not collapse them. GROUP BY produces one summary row per group; a window aggregate can attach the same group summary to every detail row.

aggregate_or_window_function(...)
OVER (
  PARTITION BY ...
  ORDER BY ...
  frame_clause
)
Three layers: PARTITION BY chooses the group, window ORDER BY chooses calculation order, and the frame chooses which rows around the current row participate.

Verified Score Lab

IDStudentClassMarks
1AaravX-A86
2MeeraX-A92
3SanaX-A92
4KabirX-B74
5VihaanX-B88
6RiyaX-B81

X-A total/average: 270/90. X-B total/average: 243/81.

Class Totals and Averages Without Collapsing Rows

SELECT student_id, student_name, class_name, marks,
       SUM(marks) OVER (
         PARTITION BY class_name
       ) AS class_total,
       ROUND(AVG(marks) OVER (
         PARTITION BY class_name
       ), 2) AS class_average
FROM advanced_scores
ORDER BY class_name, student_id;
1 | Aarav | X-A | 86 | 270 | 90.00 2 | Meera | X-A | 92 | 270 | 90.00 3 | Sana | X-A | 92 | 270 | 90.00 4 | Kabir | X-B | 74 | 243 | 81.00 5 | Vihaan | X-B | 88 | 243 | 81.00 6 | Riya | X-B | 81 | 243 | 81.00

All six detail rows remain. Without PARTITION BY, SUM and AVG would use one global six-row partition.

Running Total with an Explicit Frame

SELECT student_name, class_name, marks,
       SUM(marks) OVER (
         PARTITION BY class_name
         ORDER BY student_id
         ROWS BETWEEN UNBOUNDED PRECEDING
                  AND CURRENT ROW
       ) AS running_total
FROM advanced_scores
ORDER BY class_name, student_id;
Aarav | X-A | 86 | 86 Meera | X-A | 92 | 178 Sana | X-A | 92 | 270 Kabir | X-B | 74 | 74 Vihaan | X-B | 88 | 162 Riya | X-B | 81 | 243

The frame begins at the partition's first row and ends at the current row. Explicit ROWS gives physical row-by-row accumulation. Default frames can treat peers with equal window ORDER BY values together, so do not leave frame meaning implicit in financial or marks reports.

Compare with the Previous Row Using LAG

SELECT student_name, class_name, marks,
       LAG(marks) OVER (
         PARTITION BY class_name
         ORDER BY student_id
       ) AS previous_marks,
       marks - LAG(marks) OVER (
         PARTITION BY class_name
         ORDER BY student_id
       ) AS change_from_previous
FROM advanced_scores
ORDER BY class_name, student_id;
Aarav | X-A | 86 | NULL | NULL Meera | X-A | 92 | 86 | 6 Sana | X-A | 92 | 92 | 0 Kabir | X-B | 74 | NULL | NULL Vihaan | X-B | 88 | 74 | 14 Riya | X-B | 81 | 88 | -7

LAG reads an earlier row without a self join. LEAD reads a later row. The first row in each partition has no predecessor, so LAG returns NULL unless a supported default argument is supplied.

Reuse a Named Window

SELECT student_name, class_name, marks,
       SUM(marks) OVER w AS class_total,
       ROUND(AVG(marks) OVER w, 2) AS class_average
FROM advanced_scores
WINDOW w AS (PARTITION BY class_name)
ORDER BY class_name, student_id;

A WINDOW clause prevents repeating the same specification. Use meaningful names and confirm whether functions need identical ordering/frame semantics before sharing one definition.

Filter a Window Result in an Outer Query

Window functions are evaluated after WHERE at the same query level, so this two-stage form is required:

WITH scored AS (
  SELECT student_id, student_name,
         class_name, marks,
         AVG(marks) OVER (
           PARTITION BY class_name
         ) AS class_average
  FROM advanced_scores
)
SELECT student_name, class_name, marks
FROM scored
WHERE marks > class_average
ORDER BY class_name, student_id;
Meera | X-A | 92 Sana | X-A | 92 Vihaan | X-B | 88

Mistakes, Performance and Practice

  • Window ORDER BY does not guarantee final display order.
  • Use a deterministic ordering key for row-sensitive calculations.
  • State frames explicitly when running or moving logic matters.
  • Do not confuse window PARTITION BY with physical table partitioning.
  • Multiple different window sorts can require extra work; inspect EXPLAIN.

Practice: calculate global and class averages together; produce a two-row moving average; use LEAD to show next marks; filter above-average rows through a CTE; explain how tied ORDER BY values affect a default frame.

Official References

Syntax and behavior were checked against the official MySQL 8.4 manual. Verify plans and limits on your own server before production use.

Frequently Asked Questions

How is a window function different from GROUP BY?
GROUP BY normally collapses rows to one row per group. A window function calculates across related rows while retaining each detail row.
What does PARTITION BY do?
It divides query rows into independent windows. Omitting it creates one partition containing all rows.
Is window ORDER BY the same as final ORDER BY?
No. Window ORDER BY defines calculation order within partitions; top-level ORDER BY controls displayed result order.
Why should I specify ROWS for a running total?
An explicit ROWS frame makes row-by-row intent clear and avoids peer-sensitive default-frame surprises when ORDER BY values tie.
Can a window function be used directly in WHERE?
No at the same query level. Calculate it in a CTE or derived table, then filter in the outer query.
🔗

Share this topic with a friend

यह topic किसी दोस्त को भेजें

Found it useful? Send it to a classmate learning the same thing.

अच्छा लगा? जो दोस्त यही सीख रहा है, उसे भेज दीजिए।

💻 Live Code Editor

This page's programs are ready here — run them, edit them, and learn. No installation needed.
Powered by OneCompiler. The code loads into the editor automatically — press Run to see the output. If the editor does not open, open it in a new tab.