mysql select N max values per group
In this post:
- Get N numbers per group
- Get N max/min numbers per group
- Get N numbers per group additional constraints
- Table code and data
You could read also:
SQL select max and return N values
MySQL how to find highest and lowest value
Let say that you want to get N values or N max values per group in MySQL. For example get 3 persons from this table ( at the end you have creation code and data):
id | country | person |
---|---|---|
1 | Austria | Sue |
2 | Austria | Anie |
3 | Australia | John |
4 | Australia | Brian |
5 | UK | Jim |
6 | UK | Tim |
7 | USA | David |
8 | USA | Mike |
9 | USA | Tom |
10 | N. Korea | Joe |
11 | N. Korea | Hue |
12 | N. Korea | Rick |
13 | N. Korea | Jamy |
14 | Finland | Kimi |
Our goal is to get N persons per country(in table below we take only 1 person per country):
id | person | country |
---|---|---|
2 | Anie | Austria |
4 | Brian | Australia |
6 | Tim | UK |
9 | Tom | USA |
13 | Jamy | N. Korea |
14 | Kimi | Finland |
Get N numbers per group
In order to get N numbers per group you can use special syntax in mysql using self join and count. In this example we are getting at least 2 person from country or 1 (if the country has less than N - 2):
SELECT co.id, co.person, co.country
FROM person co
WHERE (
SELECT COUNT(*)
FROM person ci
WHERE co.country = ci.country -- controlling grouping column
AND co.id < ci.id -- controlling min or max
) < 2 -- controlling number of return per group
;
You can control the number N by changing the value: < 2 ,if you want 4 person per country you should put < 4
result:
id | person | country |
---|---|---|
1 | Sue | Austria |
2 | Anie | Austria |
3 | John | Australia |
4 | Brian | Australia |
5 | Jim | UK |
6 | Tim | UK |
8 | Mike | USA |
9 | Tom | USA |
12 | Rick | N. Korea |
13 | Jamy | N. Korea |
14 | Kimi | Finland |
Get N max/min numbers per group
The control of getting max or min records is done by this statement:
co.id < ci.id
so based on the above table for North Korea we will have:
- co.id < ci.id - this is getting maximum
id | person | country |
---|---|---|
12 | Rick | N. Korea |
13 | Jamy | N. Korea |
- co.id > ci.id - this is getting minimum
id | person | country |
---|---|---|
10 | Joe | N. Korea |
11 | Hue | N. Korea |
So getting the minimum per group is
SELECT co.id, co.person, co.country
FROM person co
WHERE (
SELECT COUNT(*)
FROM person ci
WHERE co.country = ci.country AND co.id > ci.id
) < 1
;
result:
id | person | country |
---|---|---|
1 | Sue | Austria |
3 | John | Australia |
5 | Jim | UK |
7 | David | USA |
10 | Joe | N. Korea |
14 | Kimi | Finland |
And getting the maximum per group would be:
SELECT co.id, co.person, co.country
FROM person co
WHERE (
SELECT COUNT(*)
FROM person ci
WHERE co.country = ci.country AND co.id < ci.id
) < 1
;
result:
id | person | country |
---|---|---|
2 | Anie | Austria |
4 | Brian | Australia |
6 | Tim | UK |
9 | Tom | USA |
13 | Jamy | N. Korea |
14 | Kimi | Finland |
Get N numbers per group additional constraints
If you want to use additional constraints, for example to get only males or females this should be applied on both selects - inner and outer - otherwise you will get different result
SELECT co.id, co.person, co.country
FROM person co
WHERE (
SELECT COUNT(*)
FROM person ci
WHERE co.country = ci.country AND co.id < ci.id and gender = 1
) < 2
and gender = 1;
This ensures getting the only people with gender = 1. Otherwise the result final result will include the rest of possible values for gender.
Table code and data
CREATE TABLE `person` (
`id` INT(11) NULL DEFAULT NULL,
`country` VARCHAR(50) NULL DEFAULT NULL COLLATE 'utf8_bin',
`person` VARCHAR(50) NULL DEFAULT NULL COLLATE 'utf8_bin'
)
COLLATE='utf8_bin'
ENGINE=InnoDB
;
INSERT INTO `person` (`id`, `country`, `person`) VALUES (1, 'Austria', 'Sue');
INSERT INTO `person` (`id`, `country`, `person`) VALUES (2, 'Austria', 'Anie');
INSERT INTO `person` (`id`, `country`, `person`) VALUES (3, 'Australia', 'John');
INSERT INTO `person` (`id`, `country`, `person`) VALUES (4, 'Australia', 'Brian');
INSERT INTO `person` (`id`, `country`, `person`) VALUES (5, 'UK', 'Jim');
INSERT INTO `person` (`id`, `country`, `person`) VALUES (6, 'UK', 'Tim');
INSERT INTO `person` (`id`, `country`, `person`) VALUES (7, 'USA', 'David');
INSERT INTO `person` (`id`, `country`, `person`) VALUES (8, 'USA', 'Mike');
INSERT INTO `person` (`id`, `country`, `person`) VALUES (9, 'USA', 'Tom');
INSERT INTO `person` (`id`, `country`, `person`) VALUES (10, 'N. Korea', 'Joe');
INSERT INTO `person` (`id`, `country`, `person`) VALUES (11, 'N. Korea', 'Hue');
INSERT INTO `person` (`id`, `country`, `person`) VALUES (12, 'N. Korea', 'Rick');
INSERT INTO `person` (`id`, `country`, `person`) VALUES (13, 'N. Korea', 'Jamy');
INSERT INTO `person` (`id`, `country`, `person`) VALUES (14, 'Finland', 'Kimi');