MySQL SELECT n записывает базу в GROUP BY

Допустим, у меня есть записи SQL:

Country | Number
USA | 300
USA | 450
USA | 500
USA | 100
UK  | 300
UK  | 400
UK  | 1000

И я делаю что-то вроде этого: SELECT * FROM table GROUP BY Country.
Что делать, если я хочу выбрать отображение результата с 2 наибольшим числом только в каждой стране? Как я могу архивировать это?

Результат:

Country | Number
USA | 450
USA | 500
UK  | 400
UK  | 1000

Ответ 1

Примеры данных

create table data (Country varchar(10), Number int);
insert into data select
'USA' , 300 union all select
'USA' , 450 union all select
'USA' , 500 union all select
'USA' , 100 union all select
'FR'  , 100 union all select
'FR'  , 420 union all select
'UK'  , 300 union all select
'UK'  , 400 union all select
'UK'  , 1000;

Первый вариант - это псевдо-ранг с использованием таких переменных, как Scrum Meister, но представленный здесь как один оператор

SELECT Country, Number
FROM (
    SELECT
        Number,
        @r := case when @c=country then @r+1 else 1 end rownum,
        @c := Country Country 
    FROM (select @r :=0 , @c := '') x, data
    ORDER BY Country, Number DESC
) y
WHERE rownum < 3;

Если вы используете это в интерфейсе, и вам нужно только 2 подсчета, вы можете использовать эту форму, которая возвращает подсчеты в списке (один столбец)

SELECT
    Country,
    left(x,locate(',',concat(x,','),locate(',',x)+1)-1) Numbers
FROM (
    SELECT
        a.Country,
        Group_Concat(a.Number) x
    From (
        select country, number
        from data
        order by country, number desc) a
    group by a.Country
) b

Результат

"Country";"Numbers"
"FR";"420,100"
"UK";"1000,400"
"USA";"500,450"

Если возможно возникновение связей, то этот вариант второй формы удаляет галстуки и показывает "верхние 2 разных числа на страну" в качестве записей.

SELECT distinct x.Country, x.Number
From data x
inner join
(
    SELECT
        Country,
        left(x,locate(',',concat(x,','),locate(',',x)+1)-1) Numbers
    FROM (
        SELECT
            a.Country,
            Group_Concat(a.Number) x
        From (
            select distinct country, number
            from data
            order by country, number desc) a
        group by a.Country
    ) b
) y on x.Country=y.Country
    and concat(',',y.Numbers,',') like concat('%,',x.Number,',%')
order by x.Country, x.Number Desc

Результат

"Country";"Number"
"FR";"420"
"FR";"100"
"UK";"1000"
"UK";"400"
"USA";"500"
"USA";"450"

Ответ 2

Так как MySql не имеет встроенной функции RANK, запрос может быть медленным:

SET @cRank = 0;
SET @cCoutnry = '';

SELECT Country, Number
FROM (
    SELECT Number, @cRank := IF(@cCoutnry = Country, @cRank+1, 1) AS rank, @cCoutnry := Country Country 
    FROM table
    ORDER BY Country, Number DESC
) rs
WHERE rank < 3

Ответ 3

Позволяет назвать вашу таблицу TName, тогда запрос будет.

SELECT * FROM (SELECT ROW_NUMBER() OVER (PARTITION BY X.Country) AS RowNo, *
FROM (SELECT Country, Name FROM TName ORDER BY Country, Number) X ) Y WHERE Y.RowNo <= 2