MIN() – Find the Minimum Value in a Column in MySQL

The MySQL MIN() function is an aggregate function that returns the minimum value from an expression.

Typically, the expression would be a range of values returned as separate rows in a column, and you can use this function to find the minimum value from the returned rows. If there are no matching rows, MIN() returns NULL.

For example, you can use this function to find out which city has the smallest population out of a list of cities.

Syntax

The syntax of MIN() goes like this:

MIN([DISTINCT] expr) [over_clause]

Where expr is the expression for which you want the minimum value.

The over_clause is an optional clause that works with window functions. Note that the over_clause can only be used if you don’t use the DISTINCT keyword.

The (optional) DISTINCT keyword can be used to eliminate duplicate values.

Basic Example

First, here’s the raw data that we’ll use in this example:

USE world;
SELECT Name, Population
FROM City
WHERE CountryCode = 'THA';

Result:

+-------------------+------------+
| Name              | Population |
+-------------------+------------+
| Bangkok           |    6320174 |
| Nonthaburi        |     292100 |
| Nakhon Ratchasima |     181400 |
| Chiang Mai        |     171100 |
| Udon Thani        |     158100 |
| Hat Yai           |     148632 |
| Khon Kaen         |     126500 |
| Pak Kret          |     126055 |
| Nakhon Sawan      |     123800 |
| Ubon Ratchathani  |     116300 |
| Songkhla          |      94900 |
| Nakhon Pathom     |      94100 |
+-------------------+------------+

We can use the MIN() function to find the city with the smallest population (i.e. the row with the smallest value in its population column).

USE world;
SELECT MIN(Population) AS 'Minimum Value'
FROM City
WHERE CountryCode = 'THA';

Result:

+---------------+
| Minimum Value |
+---------------+
|         94100 |
+---------------+

The GROUP BY Clause

We can use the GROUP BY clause to list out each district, along with the population of that district’s smallest city (by population):

USE world;
SELECT District, MIN(Population) AS 'Minimum Value'
FROM City
WHERE CountryCode = 'AUS'
GROUP BY District;

Result:

+-----------------+---------------+
| District        | Minimum Value |
+-----------------+---------------+
| New South Wales |        219761 |
| Victoria        |        125382 |
| Queensland      |         92273 |
| West Australia  |       1096829 |
| South Australia |        978100 |
| Capital Region  |        322723 |
| Tasmania        |        126118 |
+-----------------+---------------+

The ORDER BY Clause

We can also use the ORDER BY clause to specify a column with which to order by:

USE world;
SELECT District, MIN(Population) AS 'Minimum Value'
FROM City
WHERE CountryCode = 'AUS'
GROUP BY District
ORDER BY `Minimum Value` ASC;

Result:

+-----------------+---------------+
| District        | Minimum Value |
+-----------------+---------------+
| Queensland      |         92273 |
| Victoria        |        125382 |
| Tasmania        |        126118 |
| New South Wales |        219761 |
| Capital Region  |        322723 |
| South Australia |        978100 |
| West Australia  |       1096829 |
+-----------------+---------------+

This orders the results in ascending order, which lists the minimum value first.

Note that, when ordering by a multi-word alias (like `Minimum Value`), you need to use the backtick character (`) instead of the apostrophe (') to surround the two words.

Find the Minimum Character Length

The MIN() function isn’t limited to just columns with numerical data. You can also combine MIN() with other functions to return minimum values in other areas.

For example, using our sample data, we can find the value with the minimum number of characters in the City column:

SELECT MIN(CHAR_LENGTH(Name)) AS 'Minimum Character Length'
FROM city;

Result:

+--------------------------+
| Minimum Character Length |
+--------------------------+
|                        3 |
+--------------------------+

We can also see this by using the following query (which doesn’t involve the MIN() function):

SELECT Name, CHAR_LENGTH(Name) AS 'Character Length'
FROM city
ORDER BY `Character Length`
LIMIT 10;

Result:

+------+------------------+
| Name | Character Length |
+------+------------------+
| Ome  |                3 |
| Yao  |                3 |
| Qom  |                3 |
| Itu  |                3 |
| Tsu  |                3 |
| Ube  |                3 |
| Ise  |                3 |
| Uji  |                3 |
| Ede  |                3 |
| Ota  |                3 |
+------+------------------+

Seeing as multiple cities have the same character length, we can adjust this query to return only the distinct values:

SELECT DISTINCT CHAR_LENGTH(Name) AS 'Character Length'
FROM city
ORDER BY `Character Length`
LIMIT 10;

Result:

+------------------+
| Character Length |
+------------------+
|                3 |
|                4 |
|                5 |
|                6 |
|                7 |
|                8 |
|                9 |
|               10 |
|               11 |
|               12 |
+------------------+

Using an OVER Clause

As mentioned, the syntax allows for an OVER clause to be included in your queries. Basically, the OVER clause allows you to specify how to partition query rows into groups for processing by the window function.

Here’s an example:

SELECT 
    District,
    Name AS City,
    Population AS 'City Population',
    MIN(Population) OVER(PARTITION BY District) AS 'District Minimum'
FROM City
WHERE CountryCode = 'AUS'
ORDER BY `District Minimum` DESC;

Result:

+-----------------+---------------+-----------------+------------------+
| District        | City          | City Population | District Minimum |
+-----------------+---------------+-----------------+------------------+
| West Australia  | Perth         |         1096829 |          1096829 |
| South Australia | Adelaide      |          978100 |           978100 |
| Capital Region  | Canberra      |          322723 |           322723 |
| New South Wales | Sydney        |         3276207 |           219761 |
| New South Wales | Wollongong    |          219761 |           219761 |
| New South Wales | Newcastle     |          270324 |           219761 |
| New South Wales | Central Coast |          227657 |           219761 |
| Tasmania        | Hobart        |          126118 |           126118 |
| Victoria        | Melbourne     |         2865329 |           125382 |
| Victoria        | Geelong       |          125382 |           125382 |
| Queensland      | Townsville    |          109914 |            92273 |
| Queensland      | Brisbane      |         1291117 |            92273 |
| Queensland      | Cairns        |           92273 |            92273 |
| Queensland      | Gold Coast    |          311932 |            92273 |
+-----------------+---------------+-----------------+------------------+

This example partitions the rows by District, providing the minimum value for each partition (district). This allows you to see more granular data, such as each city’s population, along with the population of the smallest city (by population) in the same district.