2012-01-27 25 views
4

给出一个包含有由由多个地理区组织的成员赢得了在几年奖项的表,什么MySQL查询将显示在每个区的最高奖项收入来源?我可以很容易地在所有地区的前十名获奖者与此查询:mysql - 需要两个限制?

SELECT Membername, count(Award)as Number FROM awards 
GROUP BY Membername 
ORDER BY Number desc 
LIMIT 10 

但我需要与顶级收入者名单各区(有其中约90),而我还没有得到它是正确的。

我尝试这样做:

SELECT Membername, District, count(Award)as Number FROM awards 
GROUP BY Membername, District 
ORDER BY Number desc, District 
LIMIT 90 

它有一个成员准确计数,但没有显示每区之一,因此一些地区出现不止一次。我怎样才能让它列出每个地区的最高收入者,每个地区只出现一次?

回答

0

有做这一个相当普遍的方式,采用自联接。诀窍是用'没有更大的东西'来搜索'最大'搜索。正如你已经发现的

SELECT Membername, District, count(Award) as Number FROM awards 
GROUP BY Membername, District 

返回你一个很好的奖励计数结果。让我们写...来节省一点空间作为简写。

现在考虑

SELECT a.Membername, a.District, a.Number FROM (...) a LEFT JOIN (...) b 
ON a.District=b.District 
AND a.Number<b.Number 
WHERE b.Membername IS NULL 

其中...是东西上面写的。它基本上是说,在颁奖计数的每个条目(一),发现我有更多的奖项同区的所有条目(B),并且只返回(一)如果没有任何(B)的..换句话说,a是冠军。

如果在同一个分区中有多个成员具有相同的获胜次数,则需要稍微详细一点......此查询将返回所有绑定成员。你必须决定如何处理。并且注意那些根本没有任何奖励的地区......他们甚至不会出现在你的桌子上。

+0

问题是'Number'是一个派生列,是'count(Award).. GROUP BY Membername,District)''。 – 2012-01-27 03:15:03

+0

这是一个问题? – 2012-01-27 03:20:29

+0

是的,因为'count'(每个成员名称都是a.award,distrinct) 2012-01-27 03:28:26

2

您必须通过应用每个分区的“排名”来实现,然后只按每个排名抓取= 1 ...在连接位置的@LastDistrict默认为零,以防该分区基于ID。如果分区是基于字符的,则可以将其更改为=“”,而不是匹配数据类型。

为了澄清所发生的事情。 “AwardCounts”预查询可以为每个地区和每个成员提供完整的查询,无论是多少奖励。然后,按地区和会员奖励计数(降序)排序,从而将最高奖励计数定为每区第一位。

这是连接到另一个虚假别名“SQLVars”,它只是创建内联变量到名为@RankSeq和@LastDistrict的查询。因此,第一次,“DistRankSeq”将成为第一个地区的1,然后以该地区的价值填满“@LastDistrict”。同一地区的下一个条目(因为它将按照适当的顺序排列)将被分配为2,然后3等的等级......当从“最后”地区到新记录存在变化时测试后,排名重新回到1并重新开始。所以,你可以有一个区100成员,另一个5,另一个17 ...

因此,您的最终查询已全部与他们各自的队伍......现在,应用HAVING最后的地区排名= 1 ...这样做,你也可以调整必须得到每个地区前3名成员(例如)...

select 
     AwardCounts.District, 
     AwardCounts.MemberName, 
     AwardCounts.memberAwards, 
     @RankSeq := if(@LastDistrict = AwardCounts.District, @RankSeq +1, 1) DistRankSeq, 
     @LastDistrict := AwardCounts.District as ignoreIt 
    from 
     (select 
       a.district, 
       a.membername, 
       count(*) as memberAwards 
      from 
       Awards a 
      group by 
       a.district, 
       a.membername 
      order by 
       a.district, 
       memberAwards desc) AwardCounts 

     JOIN (select @RankSeq := 0, @LastDistrict = 0) SQLVars 
    HAVING 
     DistRankSeq = 1 

编辑每一次反馈 如果其聚集这就是抽空,然后我会做以下。创建一个新的表格,只包括每个区域的聚合,区域的名称和初始等级。当任何新记录被添加到该表中时,触发器然后将一个新的记录添加到聚合表计数中,然后检查该人在他们的区域内的位置并且重新更新其新的等级位置。你可以更进一步,并在每个分区有另一张“TOP”会员表,每个分区有一个人的名字。当一个新人遇到最高职位时,他们的名字被放在桌子上,覆盖最后一个人。

+0

我跑了那个查询,五分钟后,它没有完成,所以我不知道它是否工作或只是挂了phpmyadmin。该查询最终将用于交互式Web查询中,因此很长的完成时间将不起作用。它使用的表格有大约400K行,顺便说一句。 – 2012-01-27 05:24:56

+0

@GeorgeMarshall,请参阅答案中的其他评论。 – DRapp 2012-01-27 11:25:09