00:00

MySQL min() Function

Last updated: 3 min read

MIN() returns the smallest value in a set: the cheapest price, the earliest date, the lowest stock. It is the mirror image of MAX() and follows the same rules.

1. Basic MIN

Table: products (6 rows)

skunamecategorypricestockbest_before
NUT-01Cashews 500gDry Fruits1890.0082026-08-31
NUT-02Almonds 500gDry Fruits699.00NULL2026-11-30
OIL-01Groundnut Oil 1LOils250.0002026-09-30
OIL-02Olive Oil 1LOils1299.00122027-06-30
RIC-01Basmati Rice 5kgGrains899.00402027-01-31
RIC-02Sona Masoori 5kgGrains640.00552026-12-15
MIN and MAX bound the range of valuesPrices of five products laid on a line from 250 to 1890. MIN marks the left end at 250 and MAX the right end at 1890; the range is their difference.25064089912991890MIN = 250MAX = 1890range = MAX − MIN = 1640
Figure 1: MIN is the lowest value in the set, MAX the highest.
query.sql
SELECT MIN(price) AS cheapest, MIN(best_before) AS soonest_expiry, MIN(stock) AS lowest_stock FROM products;

Result: 1 row

cheapestsoonest_expirylowest_stock
250.002026-08-310

Almonds have a NULL stock, which MIN ignores. For text, MIN returns the value that sorts first:

query.sql
SELECT MIN(name) AS first_alphabetically FROM products;

Result: 1 row

first_alphabetically
Almonds 500g

2. MIN with WHERE

query.sql
SELECT MIN(price) AS cheapest_in_stock FROM products WHERE stock > 0;

Result: 1 row

cheapest_in_stock
640.00
query.sql
SELECT MIN(best_before) AS next_expiry FROM products WHERE best_before >= '2026-10-01';

Result: 1 row

next_expiry
2026-11-30

3. MIN per Group

query.sql
SELECT category, MIN(price) AS from_price, COUNT(*) AS items FROM products GROUP BY category ORDER BY from_price;

Result: 3 rows

categoryfrom_priceitems
Oils250.002
Grains640.002
Dry Fruits699.002

4. Finding the Cheapest Product in Each Category

To return the product itself, not just the price, compare each row with its category's minimum:

cheapest-per-category.sql
SELECT p.category, p.name, p.price
FROM products p
JOIN (SELECT category, MIN(price) AS min_price FROM products GROUP BY category) m
  ON m.category = p.category AND m.min_price = p.price
ORDER BY p.category;

Result: 3 rows

categorynameprice
Dry FruitsAlmonds 500g699.00
GrainsSona Masoori 5kg640.00
OilsGroundnut Oil 1L250.00

Or with a window function:

window.sql
SELECT category, name, price
FROM (SELECT p.*, MIN(price) OVER (PARTITION BY category) AS cat_min FROM products p) t
WHERE price = cat_min
ORDER BY category;

Result: 3 rows

categorynameprice
Dry FruitsAlmonds 500g699.00
GrainsSona Masoori 5kg640.00
OilsGroundnut Oil 1L250.00

5. MIN and MAX Together

query.sql
SELECT category,
       MIN(price) AS lowest,
       MAX(price) AS highest,
       MAX(price) - MIN(price) AS price_range
FROM products
GROUP BY category;

Result: 3 rows

categorylowesthighestprice_range
Dry Fruits699.001890.001191.00
Oils250.001299.001049.00
Grains640.00899.00259.00

6. MIN vs LEAST

LEAST() picks the smallest of several values in the same row, for example the lower of the list price and a promotional price:

query.sql
SELECT name, price,
       LEAST(price, price * 0.9, price - 100) AS best_offer
FROM products
WHERE category = 'Oils';

Result: 2 rows

namepricebest_offer
Groundnut Oil 1L250.00150.000
Olive Oil 1L1299.001169.100
LEAST returns NULL if any argument is NULL; MIN skips NULLs across rows.

7. Empty Sets Return NULL

query.sql
SELECT MIN(price) AS cheapest_spice, COALESCE(MIN(price), 0) AS with_default FROM products WHERE category = 'Spices';

Result: 1 row

cheapest_spicewith_default
NULL0.00

8. Practice Exercises

Exercise 1: The earliest-expiring product that is in stock, with its name.
solution.sql
SELECT name, best_before FROM products WHERE stock > 0 ORDER BY best_before LIMIT 1;

Result: 1 row

namebest_before
Cashews 500g2026-08-31
Exercise 2: Categories whose cheapest product costs more than 600.
solution.sql
SELECT category, MIN(price) AS from_price FROM products GROUP BY category HAVING MIN(price) > 600;

Result: 2 rows

categoryfrom_price
Dry Fruits699.00
Grains640.00

9. Summary

  • MIN(col) returns the smallest non-NULL value; for dates the earliest, for text the first in sort order.
  • Combine with WHERE and GROUP BY; returns NULL on an empty set.
  • Join back to a MIN sub-query or use MIN() OVER to get the full row.
  • LEAST compares values within one row.