SQL select only rows with max value on a column
ML System Design practice on Codemia
Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.
Introduction
Selecting rows that contain the maximum value of a column — especially the maximum per group — is one of the most common SQL tasks. There are several approaches: subquery with MAX(), JOIN with an aggregated subquery, window functions (ROW_NUMBER, RANK), and correlated subqueries. The best approach depends on your database engine and whether you need ties included.
Simple Case: Global Maximum
Get all rows where a column equals the overall maximum:
This returns all rows with the maximum amount. If multiple rows share the max value, all are returned.
Per-Group Maximum: The Common Problem
The more common scenario is finding the row with the maximum value in each group. For example, finding the most recent order for each customer:
Method 1: Subquery with GROUP BY
This joins the table with a subquery that finds the max date per customer. If two orders share the same max date for a customer, both are returned.
Method 2: Window Function with ROW_NUMBER (Recommended)
ROW_NUMBER() assigns 1 to the most recent order per customer. This guarantees exactly one row per group, even with ties — the database picks one arbitrarily.
Method 3: Window Function with RANK (Include Ties)
RANK() assigns the same rank to tied values. If two orders have the same highest amount for a customer, both get rnk = 1.
| Function | Ties | Result |
ROW_NUMBER() | Breaks ties arbitrarily | Exactly one row per group |
RANK() | Same rank for ties | Multiple rows possible |
DENSE_RANK() | Same rank for ties, no gaps | Multiple rows possible |
Method 4: Correlated Subquery
This is readable but can be slow on large tables because the subquery runs once per row in the outer query.
Method 5: LEFT JOIN Anti-Pattern
Find rows where no other row in the same group has a higher value:
If no row o2 exists with a later date for the same customer, then o has the max date.
Max Value with Additional Columns
Get the maximum amount and the corresponding order details per customer:
Top N Per Group
Get the top 3 orders by amount for each customer:
Database-Specific Syntax
MySQL 8.0+
MySQL 5.7 (No Window Functions)
PostgreSQL (DISTINCT ON)
DISTINCT ON is PostgreSQL-specific and returns the first row per group based on the ORDER BY.
Performance Considerations
| Method | Performance | Ties | Portability |
| ROW_NUMBER | Fast with index | No ties | SQL standard |
| JOIN + MAX subquery | Fast with index | Includes ties | All databases |
| Correlated subquery | Slow on large tables | Includes ties | All databases |
| LEFT JOIN anti-pattern | Moderate | Includes ties | All databases |
| DISTINCT ON | Fast | No ties | PostgreSQL only |
Common Pitfalls
- Ambiguous max with GROUP BY:
SELECT customer_id, MAX(amount), order_date FROM orders GROUP BY customer_iddoes not return theorder_dateof the row with the max amount — it returns an arbitraryorder_date. Use window functions or a JOIN to get correct associated columns. - Performance on large tables: Correlated subqueries execute once per outer row and can be extremely slow. Prefer JOIN or window function approaches with appropriate indexes.
- Ties: Decide upfront whether you want one row per group (use
ROW_NUMBER) or all tied rows (useRANKorJOINwithMAX). - NULL values:
MAX()ignores NULLs. If the column can be NULL, rows with NULL are excluded from the maximum calculation. UseCOALESCEif NULLs should be treated as a specific value. - Index usage: Window functions benefit from composite indexes that match the
PARTITION BYandORDER BYcolumns.
Summary
- Use
ROW_NUMBER() OVER (PARTITION BY group ORDER BY col DESC)for exactly one row per group (most versatile) - Use
RANK()orJOINwithMAX()when tied maximum values should all be returned - Avoid correlated subqueries on large tables — they are slow
- PostgreSQL's
DISTINCT ONis the most concise syntax for this pattern - Always index the partition and order columns for window function queries
Related reading
- start index at 1 for Pandas DataFrame
- Statistical approach to chess?
- Stratified splitting of pandas dataframe into training, validation and test set
- String analysis
- SQL select only rows with max value on a column
- SQL SELECT WHERE field contains words
- String Distance Matrix in Python
- Subtract mean from image

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
ML System Design practice on Codemia
Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.