【问题标题】:MySQL SELECT n records base on GROUP BYMySQL SELECT n 记录基于 GROUP BY
【发布时间】:2011-01-14 06:55:08
【问题描述】:

假设我有 SQL 记录:

国家 |数字 美国 | 300 美国 | 450 美国 | 500 美国 | 100 英国 | 300 英国 | 400 英国 | 1000

我正在做这样的事情:SELECT * FROM table GROUP BY Country.
如果,我想选择仅在每个国家/地区显示 2 个最大数字的结果怎么办?我该如何存档?

结果是:

国家 |数字 美国 | 450 美国 | 500 英国 | 400 英国 | 1000

【问题讨论】:

  • 另外,如果你在第二个位置有重复的“数字”值怎么办......你只想要那个速率的 ONE 数字实例吗?

标签: sql mysql group-by greatest-n-per-group


【解决方案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;

第一个选项是使用像 The 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
    

    【讨论】:

    • 除了使用表格中的每一行之外,您还有更好的选择吗?
    • @ajreal 想不出更快的方法,您可以尝试使用将返回最大值的子查询,并在主查询中 WHERE number
    【解决方案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
    

    【讨论】:

    • MySql 不支持 ROW_NUMER() 子句
    • 是的,你是对的。我曾想过关于 MS SQL 的问题,但我误解了(
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-11
    • 1970-01-01
    • 2010-12-11
    相关资源
    最近更新 更多